微语:代码适合中午敲,早晚出BUG
饿了么Plus组件+TS+Vue3如何使用表单重置 Vue
el-dialog组件关闭的时候清空表单内容,点击按钮也一样,改成点击事件就行了
1.引入FormInstance
import type { FormInstance } from 'element-plus'
const formRef = ref<FormInstance>()
2.定义一个空的ref挂载到el-dialog上面
let elm=ref(null)
3.绑定ref,此处的v-model用于控制是否显示弹窗 ,@closed是关闭弹窗的事件方法。
<el-dialog v-model="OrderQuery" @closed="sta(formRef)" ref="elm">
</el-dialog>
4.model为表单对象,这里也要使用ref,其中的formRef是引入进来的包创建的,在el-form-item组件上绑定prop,值为你的表单内容。
<el-form :model="numberValidateForm" label-position="top" ref="formRef">
<el-form-item label="订单号" :label-width="formLabelWidth" prop="name">
<el-input v-model="numberValidateForm.name" autocomplete="off" placeholder="请输入订单编号" />
</el-form-item>
</el-form>
5.触发关闭窗口回调
let sta = (formEl: FormInstance | undefined) => {
if (!formEl) return
formEl.resetFields()
}
完整代码:去掉了多余的,留下了最重要的,方便观察
<el-form :model="numberValidateForm" ref="formRef">
<el-form-item prop="name">
<el-input v-model="numberValidateForm.name"/>
</el-form-item>
</el-form>
<script lang="ts" setup>
//引入包
import type { FormInstance } from 'element-plus'
const formRef = ref<FormInstance>()
const numberValidateForm = ref({
name: '',
})
//关闭回调
const resetForm = (formEl: FormInstance | undefined) => {
if (!formEl) return
formEl.resetFields()
}
</script>
Element-Plus分页组件默认是英文如何改成中文 Vue
原图
修改之后:
解决办法:
在main.js中加入如下代码:
import zhLocale from "element-plus/es/locale/lang/zh-cn";
app.use(ElementPlus, { locale: zhLocale })
Vue3组件的二次封装以及插槽、传值的使用 Vue
使用ElementUI的Card的组件的时候,很多地方都会用到卡片这个组件,以及修改一下他默认的样式,进行了二次的封装。
效果图如下:
这里封装主要是针对表格处理的,接收了一个标题参数,和2个具名插槽,一个是是否导出表格按钮,一个是表格内容。
子组件代码如下:
<template>
<el-card class="box-card">
<template #header>
<div class="card-header">
<span class="title">{{ props.title }}</span>
<slot name="button"></slot>
</div>
</template>
<slot name="table"></slot>
</el-card>
</template>
<script lang="ts" setup>
let props = defineProps({
title: {
type: String,
default: '这是标题'
},
})
</script>
<style lang="scss" scoped>
.card-header {
display: flex;
justify-content: space-between;
align-items: center;
}
.text {
font-size: 14px;
}
.item {
margin-bottom: 18px;
}
.box-card {
width: 100%;
}
:deep(.el-table .cell) {
text-align: center;
}
.card-header .title {
position: relative;
color: #35a2ef;
padding-left: 10px;
}
.card-header .title::after {
content: "";
display: block;
width: 4px;
height: 15px;
background-color: #35a2ef;
position: absolute;
left: 0px;
top: 5px;
}
</style>
父组件代码如下:
<template>
<MyCart title="账号管理">
<template #button>
<el-button type="primary" @click="Table">
导出表格<el-icon class="el-icon--right">
<Download />
</el-icon>
</el-button>
</template>
<template #table>
<!-- v-slot:table -->
<el-table :data="userList" border style="width: 100%">
<el-table-column type="selection" prop="date" fixed />
<el-table-column prop="id" label="ID" />
<el-table-column prop="account" label="账号" />
<el-table-column prop="userGroup" label="用户组" />
<el-table-column prop="ctime" label="创建时间">
<template #default="props">
<span>{{ props.row.ctime }}</span>
</template>
</el-table-column>
<el-table-column label="操作" width="120" fixed="right">
<template #default>
<el-button link type="primary" size="small">编辑</el-button>
<el-button link type="primary" size="small">删除</el-button>
</template>
</el-table-column>
</el-table>
</template>
</MyCart>
</template>
<script lang="ts" setup>
import MyCart from '../../components/MyCard.vue'
import * as XLSX from 'xlsx'//表格导入导出插件
import { ref, computed, reactive } from 'vue';
import { $_UsersList } from '../../apis/user'
interface user {
"id": number,//账号ID
"ctime": string,//用户名称
"account": string,//注册时间
"userGroup": string,//管理权限
"imgUrl": string//头像地址
}
let userList = ref<Array<user>>([])
$_UsersList({
currentPage: 1,
pageSize: 10
}).then(res => {
// 处理时间
res.data.data.map((v: user) => {
v.ctime = new Date(v.ctime).toLocaleString()
});
userList.value = res.data.data
})
let Table = () => {
//1. 创建一个工作簿
const workBook = XLSX.utils.book_new()
// 2. 创建工作表 worksheet
const workSheet = XLSX.utils.json_to_sheet(userList.value)
// 3. 将工作表放入工作簿中
XLSX.utils.book_append_sheet(workBook, workSheet)
XLSX.writeFile(workBook, `账号列表.xlsx`, {
bookType: 'xlsx'
})
}
</script>
<style lang="scss" scoped></style>
总结:
1.父传子使用的时候defineProps,在Vue3里面在setup下不需要引入就可以使用
例如:子组件接收参数
let props = defineProps({
title: {
type: String,
default: '这是标题'
},
})
父组件传递只需要这样:
<MyCart title="传递的内容"> </MyCart>
2.具名插槽:如果需要插入内容的时候,并且想指定到某个位置需要给插槽定义名字。
例如:在组件通过name定义一个插槽名字为button,这个插槽放到上面位置,传过来的东西就会显示在什么地方,
<slot name="button"></slot>
父组件如下:在vue3里面需要使用template进行包裹 后面跟#定义的名字就可以,或者 v-slot:button 也可以
<template #button>
这里面是内容
</template>
<template v-slot:button>
这里面是内容
</template>
vue3写了一个路由标签导航栏组件 Vue
vue3里面引入就可以使用,vue2需要注册一下在调用。
大致思路,进入页面的时候监听路由,判断当前路由的地址,然后把这个地址用来做激活样式匹配,接下来就是点击事件,点击谁就把激活样式给谁,其次是删除如果删除的是第一个,下次跳转默认下标为0的标签,并且附带激活样式,如果不是就跳转上一个也是index+1。这里面用了一点ts语法!
<LabelNav />
<script lang="ts" setup>
import LabelNav from '../components/LabelNav.vue'
</script>
效果展示:
完整代码
<template>
<div class="DynamicMenu">
<el-scrollbar>
<div class="scrollbar-flex-content">
<div @click="switching(item.to)" :class="{ 'DynamicMenu-span': true, 'active': item.to == path }"
v-for="(item, index) in label " :key="index">
<span>{{ item.title }}</span>
<span @click="removeTag(index); $event.stopPropagation()" class="ax"></span>
</div>
</div>
</el-scrollbar>
</div>
</template>
<script setup lang="ts">
import { reactive, watch, ref } from 'vue';
import { useRoute, useRouter } from 'vue-router';
let $route = useRoute()
let $router = useRouter()
interface LabelItem {
title: string;
to: string;
}
let path = ref()
let label = reactive<LabelItem[]>([
])
path.value = $route.path
// 页面加载的时候读取本地tab标签
const storedTabs = localStorage.getItem('tab');
if (storedTabs) {
const newTabs = JSON.parse(storedTabs) as LabelItem[];
newTabs.forEach(newTab => {
const hasDuplicate = label.some(item => item.title === newTab.title);
if (!hasDuplicate) {
label.push(newTab);
}
});
} else {
label.push({ title: '后台首页', to: '/index' })
localStorage.setItem('tab', JSON.stringify(label))
}
// 监听路由变化,进行激活样式更改和标签存储
watch(() => $route.meta.title, (newTitle) => {
path.value = $route.path//激活样式
let tis: string = newTitle as string;
// 检查是否存在相同的项,存储标签
const hasDuplicate = label.some(item => item.title === tis);
if (!hasDuplicate) {
label.push({ title: tis, to: $route.path });
localStorage.setItem('tab', JSON.stringify(label))
}
});
// 删除标签
let removeTag = (index: number) => {
if (label.length === 1) {
return;
} else {
label.splice(index, 1);
// 如果删除的是第一个标签,则跳转下一个,反之则跳转上一个
if (index === 0) {
path.value = label[0].to;
$router.push(label[0].to);
} else {
path.value = label[index - 1].to;
$router.push(label[index - 1].to);
}
localStorage.setItem('tab', JSON.stringify(label));
}
}
// 点击标签跳转
let switching = (to: string) => {
path.value = to
$router.push(to)
}
</script>
<style lang="scss" scoped>
.DynamicMenu {
width: 100%;
height: 30px;
background-color: #f5f7fa;
position: relative;
top: 0;
display: flex;
align-items: center;
.DynamicMenu-span {
height: 25px;
min-width: 100px;
background-color: #35a2ef;
display: flex;
align-items: center;
justify-content: center;
margin: 0 2px;
padding: 0 10px;
font-size: 12px;
color: #fff;
position: relative;
span {
height: 100%;
line-height: 25px;
}
}
.ax {
width: 20px;
height: 20px;
position: relative;
position: absolute;
right: 0;
}
.DynamicMenu-span .ax::after,
.DynamicMenu-span .ax::before {
content: "";
width: 2px;
height: 10px;
top: 6px;
border-radius: 50%;
background-color: #fff;
right: 10px;
position: absolute;
transition: transform 0.3s ease;
}
.DynamicMenu-span .ax::after {
transform: rotate(-45deg);
}
.DynamicMenu-span .ax::before {
transform: rotate(45deg);
}
.DynamicMenu-span .ax:hover::after {
transform: rotate(45deg);
background-color: #ff0000;
}
.DynamicMenu-span .ax:hover::before {
transform: rotate(-45deg);
background-color: #ff0000;
}
.active {
background-color: white;
color: #35a2ef;
border: 1px solid #35a2ef;
}
}
.scrollbar-flex-content {
display: flex;
}
.scrollbar-demo-item {
flex-shrink: 0;
display: flex;
align-items: center;
justify-content: center;
width: 100px;
height: 50px;
margin: 10px;
text-align: center;
border-radius: 4px;
background: var(--el-color-danger-light-9);
color: var(--el-color-danger);
}
</style>
Vue中API接口如何二次封装Axios进行高效开发 Vue
1.src目录下新建 utlis文件夹 ->axios.ts
引入axios插件,创建公共服务器IP ,设置请求拦截器和相应拦截器,最后暴露出去
import axios from "axios"
export const SERVER_IP = 'http://XXXXXX/'
export const request = axios.create({
baseURL: SERVER_IP,
timeout: 6000,
})
//请求拦截器
request.interceptors.request.use()
//相应拦截器
request.interceptors.response.use()
2.src目录下创建 apis文件夹->里面存储分类接口例如用户接口,登录接口:login.ts
引入封装的axios,进行接口的一个封装,然后暴露出去
import { SERVER_IP, request } from '../utlis/axios'
import type { Login } from './interface'
// 登录接口
export const $_checkLogin = (data: Login) => {
return request({
url: '/users/checkLogin',
method: 'POST',
data
})
}
//获取列表
export const $_UsersList = (params: userList) => {
return request({
url: '/users/list',
method: 'GET',
params
})
}
3.在需要使用接口的页面只需调用封装的api也就是apis文件夹里面的文件例如:login.ts
<script lang="ts" setup>
import { reactive } from 'vue';
import { $_checkLogin } from '../apis/login'
let form = reactive({
account: '',
password: ''
});
let onSubmit = () => {
$_checkLogin(form).then(res => {
//请求成功之后操作
})
}
</script>
封装的好处方便我们后期维护管理API,如果吧api直接在写每个页面进行直接发请求,文件多起来了,就变的难以维护,如果用到了相同的请求也会造成代码冗余度过高。
封装之后对接口统一进行管理,更方便直观的查看API和维护,也降低了代码冗余度,和可读性。
以上示例都是基于Vue3+Ts写的,用Vue2+JS封装流程也是一样,只是不需要reactive这种响应式
vue3如何使用动态class切换 Vue
这里写的是一个旋转按钮使用的是elementPlus
vue3动态class三目预算:class="isRotated ? 'rotate' : 'reverseRotate'"通过点击事件给变量取反来实现class样切换
HTML
<div class="numE" @click="numE">
<el-icon ref="numElement" color="#fff" size="30px" :class="isRotated ? 'rotate' : 'reverseRotate'">
<Expand />
</el-icon>
</div>
CSS
.rotate,
.reverseRotate {
transition: transform 0.5s ease;
}
.rotate {
transform: rotate(180deg);
}
.reverseRotate {
transform: rotate(0deg);
}
JS
import { ref } from 'vue'
let isRotated = ref(false)
let numE = () => {
isRotated.value = !isRotated.value;
}
vue3的动态css v-bind() Vue
vue3支持 css中支持v-bind来绑定动态样式值,例如:
<template>
<span>123</span>
</template>
<script setup>
let color="#fff"
</script>
<style lang="scss" scoped>
span {
background-color: black;
color: v-bind(color);
}
</style>
聊一聊 Vue3的那些事情 程序畅言
这是一个备受期待的互联网技术!如果你对网页开发感兴趣,那你肯定听说过 Vue,它是一个流行的前端框架,用于构建灵活且高效的用户界面。
那么,Vue 3究竟有什么新奇的东西呢?首先,让我告诉你一个非常重要的概念:Composition API(组合 API)。Vue 3 引入了这个全新的 API,它让你能够更好地组织和重用代码。以前,在 Vue 2 中,我们可能需要使用 mixins 和高阶组件等方式来实现代码重用,但是这些方式有时候会让代码变得难以理解和调试。而 Composition API 则采用了一种更加直观的方式,让你可以根据逻辑功能(而不是组件)对代码进行组合,这样可以更加灵活和可读性。
除了 Composition API,Vue 3 还带来了更强大的性能优化。现在,Vue 3 使用 Proxy 代替了 Object.defineProperty 来实现响应式系统,这使得数据的变化能够更加高效地追踪和更新。这意味着,当你改变一个数据时,Vue 3 能够更快地检测到变化并且只重新渲染受到影响的部分,从而提高了应用程序的性能。
另外一个令人兴奋的功能是 Vue 3 的虚拟 DOM(Virtual DOM)改进。Vue 3 在虚拟 DOM 的实现上进行了优化,它在渲染和更新时能够更加高效地处理 DOM 的操作,进一步提升了应用程序的性能。
总而言之,Vue 3 给我们带来了更加强大和易用的工具,让我们能够更好地构建现代化的互联网应用程序。无论你是前端开发新手还是经验丰富的工程师,Vue 3 都能为你带来更高效和愉悦的开发体验