Vue3-ElementPlus

📅 2026/7/15 14:20:49 👁️ 阅读次数 📝 编程学习
Vue3-ElementPlus

目录

ElementPlus按需导入

Icon图标导入

组件中英文切换

ElementPlus常见组件

Layout布局

Form表单

表单校验

自定义校验规则

表单提交预校验(Form Exposes)

重置表单

行内表单

表单组件

多选组合

日期选择器

年份选择器和月份选择器联动

禁用某些年份、月份或日期

input输入框

textarea文本域

插槽自定义label

消息提示

Container 布局容器

​编辑

Menu菜单

下拉菜单

指令事件

消息弹出框

卡片

表格

序号

自定义列

Table插槽

整行的点击事件

设置当前选中行高亮颜色

按钮

加载

空状态

对话框

Link链接

分页

抽屉

上传

单选框

弹窗

文件上传

统计组件


ElementPlus按需导入

1.安装

pnpm add element-plus

全局导入:

import ElementPlus from 'element-plus' import 'element-plus/dist/index.css' app.use(ElementPlus)

2.配置按需导入:

官方文档:快速开始 | Element Plus

按照官网按需导入中的自动导入步骤来进行

pnpm add -D unplugin-vue-components unplugin-auto-import

观察Vite代码与原vite文件的差别,将原vite文件中没有的,复制粘贴到合适的位置

3.直接使用组件,样式就是element-Plus的

4.默认components下的文件也会被自动注册

不需要再导入也能使用

5.使用某组件时显示:

可能时安装的版本不够高,需要安装组件所属版本的更高阶

pnpm add element-plus@latest

查看当前版本:

pnpm info element-plus version

Icon图标导入

1.安装

pnpm i @element-plus/icons-vue

官网参考: Icon 图标 | Element Plus

2.使用

先导入

import { 图标名 } from '@element-plus/icons-vue'

在el-input输入框里使用

<el-input :prefix-icon="Lock"></el-input>

组件中英文切换

全局配置中文

<script setup> import zhCn from 'element-plus/dist/locale/zh-cn.mjs' </script> <template> <div> <!--App.vue只需要留一个路由出口router-view即可--> <el-config-provider :locale="zhCn"> <router-view></router-view> </el-config-provider> </div> </template>

ElementPlus常见组件

官方文档:Button 按钮 | Element Plus

Layout布局

类似栅格网格系统,el-row表示一行,一行分成24份;el-col在el-row中使用,el-col表示列,其中:span="x"代表在一行中占x份,:offset="x"代表左侧margin的份数

Form表单

el-form为整个表单组件;el-form-item为表单的一行,其中label="xx"设置行标签

el-input加上show-password可以实现切换密码可见

<el-input type="password" show-password></el-input>

表单校验

校验规则:

(1)在el-form上配置:model="ruleFormRef"绑定的是整个form的数据对象

(2)在el-form上配置:rules="rules"绑定的是整个rules规则对象

(3)在el-form-item上配置props="name"配置生效的是哪个校验规则(和rules中的字段对应)

(4)表单元素上配置v-model="ruleForm.name"给表单元素绑定form的子属性

label-width="宽度"控制前面标题的宽度,方便后面的内容对齐,不能写auto会控制台警告

const formModel = ref({ username: '', password: '', repassword: '', telphone: '' }) //整个表单的校验规则 const rules = { username: [ { required: true, //非空校验 message: '请输入用户名', //消息提示 trigger: 'blur' //触发时机,两个值:blue表示失去焦点,一般在input组件中使;change为值改变,一般在选择框中使用 }, { min: 5, //长度限制 max: 10, message: '用户名必须是5-10位的字符', trigger: 'blur' } ], password: [ { required: true, message: '请输入密码', trigger: 'blur' }, { pattern: /^\S{6,15}$/, //正则表达式 \S非空字符 message: '密码必须是6-15位的非空字符', trigger: 'blur' } ], telphone: [ { pattern: /^[0-9]*$/, message: '请输入纯数字手机号码', trigger: 'blur' } ] }

切换页面(例如语言切换)会自动触发校验规则,用户体验感差

优化方法:给el-form组件添加

:validate-on-rule-change="false"
<el-form :model="ruleForm" :rules="rules" :validate-on-rule-change="false"> </el-form>
自定义校验规则

validator: (rule, value, callback)

(1)rule 当前校验规则相关的信息

(2)value 所校验的表单元素目前的表单值

(3)callback 无论成功还是失败,都需要 callback 回调

--callback()校验成功

--callback(new Error(错误信息)) 校验失败

默认是实时触发,要修改成失焦触发

const rules = { repassword: [ { validator: (rule, value, callback) => { if (value !== formModel.value.password) { callback(new Error('两次输入的密码不一致')) } else { callback() //校验成功,也需要callback } }, trigger: 'blur' } ] }
表单提交预校验(Form Exposes)

首先需要获取form组件

<script setup> import { ref } from 'vue' //获取dom元素 const form = ref() </script> <template> <el-form ref="form"></el-form> </template>

为提交按钮添加点击事件register

const register = async () => { //注册成功之前,先进行校验,校验成功->请求,校验失败->自动提示 await form.value.validate() console.log('开始注册请求') }

重置表单
this.$refs.表单ref名.clearValidate()//移除整个表单的校验结果 this.$refs.表单ref名.clearValidate('prop属性')//移除某个prop属性的校验结果
表单ref名.value.resetFields()//将表单的所有字段重置为初始值同时移除表单的校验结果

注:只会重置带有prop属性的项,并且最外层el-form要绑定上v-model,里面的每个小项也要和最外层v-model里的小项对应上

表单需要先渲染出来才能使用,有时候会显示报错

dialogVisible.value控制子组件的显示,在子组件打开时重置一下表单

await nextTick()是等表单渲染完成后再触发下面的

watch( () => dialogVisible.value, async (val) => { if (!val) return await nextTick() formRef.value?.resetFields() } )
行内表单

<el-form inline></el-form>
表单组件
多选组合
const couponCheckList = ref() <el-checkbox-group v-model="couponCheckList"> <div v-for="coupon in couponListData.data.valid_coupons" :key="coupon.coupon_code" > <el-checkbox :checked="true" :label="coupon.coupon_code" :value="coupon.coupon_code" @change="isCheck = true" /> </div> </el-checkbox-group>
日期选择器
<el-date-picker v-model="applyDate" type="daterange" range-separator="到" start-placeholder="开始日期" end-placeholder="结束日期" :teleported="false" value-format="YYYY-MM-DD" />

value-format设置存储的日期格式,设置了这个之后v-model里存储的值也是对应的,不然还需要修改格式

format是设置在页面里显示的格式

年份选择器和月份选择器联动
<el-form-item label="年份"> <el-date-picker v-model="year" type="year" :teleported="false" @change="handleYearChange" /> </el-form-item> <el-form-item label="月份"> <el-date-picker class="monthSelecter" v-model="month" type="month" :teleported="false" format="MM" @change="handleMonthChange" /> </el-form-item>
const year = ref() const month = ref() const handleYearChange = (value) => { // 年份选择器选择后把年份赋值给月份选择器 if (value && month.value) { const newDate = new Date(month.value) // 复制当前日期对象 newDate.setFullYear(value.getFullYear()) // 设置新的年份 month.value = newDate } } const handleMonthChange = (value) => { // 月份选择器选择后把年份赋值给年份选择器 if (value) { year.value = String(value.getFullYear()) } }

获取绑定年份选择器所选择的具体年份:

new Date(year.value).getFullYear()
禁用某些年份、月份或日期

禁用某些年份:

const disabledDate = (time) => { // 获取当前日期的年份 const year = new Date(time).getFullYear() // 禁用2018年以前和明年后的年份 return year < 2018 || year > new Date().getFullYear() + 1 } <el-date-picker v-model="year" type="year" :teleported="false" :disabled-date="disabledDate" />

只允许选择今天、昨天、前天:

const disabledDate = (time) => { // 获取今天的日期 const today = new Date() // 设置时间为0点,确保比较时不考虑时间部分 today.setHours(0, 0, 0, 0) // 获取昨天和前天的日期 const yesterday = new Date(today) yesterday.setDate(today.getDate() - 1) const twoDaysAgo = new Date(today) twoDaysAgo.setDate(today.getDate() - 2) // 如果日期不在今天、昨天和前天之内,则禁用该日期 return ( time.getTime() > today.getTime() || time.getTime() < twoDaysAgo.getTime() ) }

获取当年年份:

new Date().getFullYear()
input输入框

设置为只读,但是可编辑;disabled是不可编辑不可复制

textarea文本域

设置自适应高度,设置autosize可根据文本高度自适应

:autosize="{ minRows: 0 }"

select选择器

multiple:多选

collapse-tags:多选时折叠除第一个的标签

max-collapse-tags="数量":设置前几个数量的标签不折叠

使用插槽自定义显示的内容:显示所选择的value值也就是wh_code

<el-select style="width: 450px" v-model="formData.selectStore" multiple :teleported="false" > <el-option v-for="item in shopList" :label="item.wh_code + ' ' + item.code" :value="item.wh_code" :key="item.wh_code" /> <template #label="{ value }"> {{ value }} </template> </el-select>
插槽自定义label
<el-form-item label="一级审批邮箱" prop="firstEmail"> <template v-slot:label> <div style="display: grid"> <span style="line-height: 10px">一级审批邮箱 </span> <span style="color: rgba(0, 0, 0, 0.45)"> (小区经理) </span> </div> </template> <el-input v-model="params.firstEmail" /> </el-form-item>

消息提示

ElMessage({ message: '成功', type: 'success', }) 或 ElMessage.success('成功')

错误:‘ElMessage’ is not defined.

解决:如果使用的是按需导入,import ElMessage就会导致失效,应该在.eslintrc.cjs文件中添加语句声明全局变量名

globals: { ElMessage: 'readonly', ElMessageBox: 'readonly', ElLoading: 'readonly' }

Container 布局容器

Menu菜单

el-menu为整个菜单组件,其中active-text-color代表选中时的颜色,:default-active="$route.path"配置默认高亮的菜单项,router开启就可以点击跳转写在el-menu-item的index中的路径

el-menu-item为菜单项

<el-menu active-text-color="#ffd04b" background-color="#232323" :default-active="$route.path" text-color="#fff" router > <el-menu-item index="/article/channel"> <el-icon><Management /></el-icon> <span>文章分类</span> </el-menu-item> <el-menu-item index="/article/manage"> <el-icon><Promotion /></el-icon> <span>文章管理</span> </el-menu-item> <el-sub-menu index="/user"> <!--多级菜单的标题 - 具名插槽title--> <template #title> <el-icon><UserFilled /></el-icon> <span>个人中心</span> </template> <!--展开的内容 - 默认插槽--> <el-menu-item index="/user/profile"> <el-icon><User /></el-icon> <span>基本资料</span> </el-menu-item> <el-menu-item index="/user/avatar"> <el-icon><Crop /></el-icon> <span>更换头像</span> </el-menu-item> <el-menu-item index="/user/password"> <el-icon><EditPen /></el-icon> <span>重置密码</span> </el-menu-item> </el-sub-menu> </el-menu>

下拉菜单

指令事件

消息弹出框

import { ElMessageBox } from 'element-plus'
ElMessageBox.confirm('你确认要进行退出么', '温馨提示', { type: 'warning', confirmButtonText: '确认', cancelButtonText: '取消', dangerouslyUseHTMLString: true//提示文字可以使用HTML样式,比如使用换行符<br/> })

注意:如果使用的是按需导入,import ElMessage就会导致失效,应该在.eslintrc.cjs文件中添加语句声明全局变量名

globals: { ElMessage: 'readonly', ElMessageBox: 'readonly', ElLoading: 'readonly' }

点击取消或右上角×时,控制台会弹出报错

需要增加.catch语句

ElMessageBox.confirm('你确认要进行退出么', '温馨提示', { type: 'warning', confirmButtonText: '确认', cancelButtonText: '取消' }) .then(() => { }) .catch(() => { })

卡片

<template> <el-card class="page-container"> <template #header> <div class="header"> <span>文件传送</span> <div class="extra"> <el-button type="primary">选择文件</el-button> </div> </div> </template> <slot></slot> </el-card> </template> <style lang="scss" scoped> .page-container { min-height: 100%; box-sizing: border-box; .header { display: flex; justify-content: space-between; align-items: center; } } </style>

表格

el-table-column是一列,其中label是标题,prop是去对象中找对应的属性做渲染,width是宽度

表格中数据不显示:1)绑定的数据是不是响应式的 2)有没有加setup语法糖

序号

<el-table-column lable="序号" type="index"></el-table-column>
自定义列

scope.row可以拿到行信息,scope.row.属性名可以拿到某行信息里的,scope.$index是下标

或者函数传递参数

<el-table-column label="操作" width="150"> <template #default="{ row, $index }"> <el-button @click="onEditChannel(row, $index)" :icon="Edit" circle type="primary" plain > </el-button> <el-button @click="onDelChannel(row, $index)" :icon="Delete" circle type="danger" plain > </el-button> </template> </el-table-column>

根据某列的值显示对应的内容

<el-table-column label="申请状态" prop="status"> <template #default="{ row }"> <!-- 使用 v-slot 语法 --> <span v-if="row.status === 0">未审批</span> <span v-else>已重启</span> </template> </el-table-column>
Table插槽

<template #empty>暂无数据</template>

整行的点击事件
@row-click="handleRowClick"

const handleRowClick = (row, column, event) => { console.log('行点击事件触发', row); const rowIndex = 表格数组.indexOf(row) // 使用indexOf获取行数据在数组中的位置 console.log('所点击的行的index', rowIndex) };

双击事件

@row-dblclick="RowDbclick" const RowDbclick = (row) => {}

如果在表格中增加操作栏触发点击事件,会和这个功能冲突,那么可以这样写点击事件:

@click.stop=""

设置当前选中行高亮颜色

在表格里添加以下代码:

:highlight-current-row="true"

设置选中某一行

table表格的ref值.setCurrentRow(table关联的数据表[行数])

获取选中的行信息

<el-table ref="singleTableRef"></el-table> const singleTableRef= ref(null); let row = singleTableRef.value.store.states.currentRow.value;

设置高亮的颜色

//修改表格所选中的行的高亮颜色 :deep(.el-table__body tr.current-row > td) { background: var(--el-color-warning-light-9) !important; }
格式化数字显示
const formatNumber = (row, column) => { return Math.floor(row[column.property]) .toString() .replace(/\B(?=(\d{3})+(?!\d))/g, ',') // 不保留小数且增加千分位格式 } <el-table-column label="员工目标" prop="target" :formatter="formatNumber" ></el-table-column>
实现默认排序

以code列升序排列:

<el-table :default-sort="{ prop: 'code', order: 'ascending' }"> </el-table>

ascending(升序)或descending(降序)

按钮

type控制颜色;plain控制镂空效果;roundcircle控制形状

@keydown.enter.prevent//禁用按钮回车触发 @keydown.space.prevent//禁用按钮空格触发
:loading="变量"//实现加载样式

加载

v-loading="true"

空状态

<el-empty description="没有数据"></el-empty>

对话框

Link链接

<el-link>...</el-link>

分页(页码组件)

v-model:current-page代表当前页码,v-model:page-size代表每页条数,:page-sizes可供用户选择的每页条数(注意要包含当前设置的每页条数),layout代表菜单栏(顺序和个数都是一一对应的),@size-change每页条数变化时触发的事件,@current-change当前页变化时触发的事件

更新:Element Plus 已废弃@size-change@current-change,改为使用@change

total的值一定要为数字类型,不然控制台会报错

total.value = Number(变量) || 0

抽屉

v-model控制显示与隐藏,:direction控制方向(默认从右往左),size控制大小

上传

action配置了后台接口地址,请求方式为post,请求参数name="file"

可以通过下面的API修改默认配置

:on-change控制上传事件,

const onSelectFile = (uploadFile) => { console.log('图片链接:',uploadFile.raw) }

js控制显示上传

上传组件ref.$el.querySelector('input').click()

单选框

v-model双向绑定数据

value单向获取选项数据(不能修改)

修改选项使用@input

弹窗

出现弹窗闪现一下,立刻消失的问题,解决方法:

增加一个setTimeout延时

setTimeout(() => { this.$confirm('此操作将会清空原有数据, 是否继续?', '提示', { confirmButtonText: '确定', cancelButtonText: '取消', type: 'warning' }).then(() => { //确定后执行 }).catch(() => { //取消后执行 }); }, 200)

文件上传

使用el-upload做了一个只允许上传一份excel文件的组件,并且上传新的文件会覆盖原文件

<script setup> import { UploadFilled } from '@element-plus/icons-vue' import { ref } from 'vue' const dialogVisible = ref(false) const title = ref() const isEdit = ref(false) const uploading = ref(true) const fileList = ref([]) const open = async (t, s) => { dialogVisible.value = true //显示抽屉 title.value = t isEdit.value = s } //上传文件组件发生变化时 const handleChange = (file) => { if (!isXLSXCSV(file.name)) { ElMessage({ message: '仅允许上传excel/csv文件', type: 'warning' }) fileList.value = [] return } uploading.value = false fileList.value = [file.raw] } //移除文件时 const handleRemove = () => { uploading.value = true fileList.value = [] } //超出最大文件数时 const handleExceed = (file) => { if (!isXLSXCSV(file[0].name)) { ElMessage({ message: '仅允许上传excel/csv文件', type: 'warning' }) return } ElMessage({ message: '仅允许上传一份文件,已覆盖原文件', type: 'warning' }) fileList.value = [file[0]] } const onSubmit = () => {} const isXLSXCSV = (link) => { return /.xlsx$/.test(link) || /.csv$/.test(link) } defineExpose({ open }) </script> <template> <el-dialog v-model="dialogVisible" :title="title" width="50%"> <el-upload ref="uploadrefss" :file-list="fileList" action="#" accept=".xlsx,.csv" class="upload-demo" drag :limit="1" :auto-upload="false" :on-change="handleChange" :on-remove="handleRemove" :on-exceed="handleExceed" > <el-icon class="el-icon--upload"><upload-filled /></el-icon> <div class="el-upload__text">拖拽文件至这里或 <em>点击上传</em></div> <template #tip> <div class="el-upload__tip"> 限制一份excel/csv文件,下一个文件会覆盖上一个文件 </div> </template> </el-upload> <template #footer> <span class="dialog-footer"> <el-button @click="dialogVisible = false" color="#A88D5B" plain >取消</el-button > <el-button type="primary" @click="onSubmit" color="#A88D5B" style="color: white" :disabled="uploading" > 确认导入 </el-button> </span> </template> </el-dialog> </template> <style> .el-dialog__headerbtn:focus .el-dialog__close, .el-dialog__headerbtn:hover .el-dialog__close { color: #7e6934 !important; } </style>

统计组件

显示到小数点后两位

const formatter = (value) => { return value.toFixed(2) } <el-statistic title="超出预期(%)" :value="变量" :formatter="formatter" />