实战总结:ElementPlus 组件库
本文是对《15-前端Web实战(Vue工程化+ElementPlus)》讲义中 ElementPlus 部分 的总结,结合实战项目 vue-project03-ElementPlus 的代码。
这一天的目标:掌握 ElementPlus 组件库的引入配置,学会从官网拷贝常用组件(表格/分页/对话框/表单)并改造使用。
学习方式:不背 API,掌握”官网找 → 复制 → 改”的流程。
一、ElementPlus 介绍
- Element Plus:饿了么前端团队提供的基于 Vue3 的网站组件库。
- 官网:https://element-plus.org/zh-CN/
- 作用:提供按钮、表格、表单、对话框等现成组件,快速构建好看的后台页面。
- 学习理念(后台开发者视角):学会从官网拷贝组件代码 → 粘贴到项目 → 做修改即可,不要求死记。
二、快速入门
1. 安装组件库
1
| npm install element-plus@2.4.4 --save
|
实战中 package.json 里是 "element-plus": "^2.4.4",已安装好。
2. main.js 配置(关键)
实战项目 main.js 完整代码:
1 2 3 4 5 6 7 8 9
| import './assets/main.css' import ElementPlus from 'element-plus' import 'element-plus/dist/index.css'
import zhCn from 'element-plus/es/locale/lang/zh-cn' import { createApp } from 'vue' import App from './App.vue'
createApp(App).use(ElementPlus, { locale: zhCn }).mount('#app')
|
3. 讲义 vs 实战:locale 引入路径差异
| 来源 |
引入路径 |
| 讲义写法 |
import zhCn from 'element-plus/dist/locale/zh-cn.mjs' |
| 实战写法 |
import zhCn from 'element-plus/es/locale/lang/zh-cn' |
⚠️ 两种路径都能实现中文化,实战用的是 es 目录下的源码版本。如果一种路径报错,换成另一种试试。
4. 两种 main.js 写法对比
1 2 3 4 5 6 7
| const app = createApp(App) app.use(ElementPlus, { locale: zhCn }) app.mount('#app')
createApp(App).use(ElementPlus, { locale: zhCn }).mount('#app')
|
两者等价,链式写法更简洁,但要注意 mount 必须放在最后。
5. 使用流程(通用套路)
1 2 3 4 5
| 1. 官网找组件 → 复制 <template> 代码 2. 复制 <script> 中的数据和函数 3. 复制 <style> 样式(如有) 4. 在 App.vue 中 import 并使用 5. 按需求改属性、改数据、改文案
|
三、常见组件实战(基于 vue-project03)
以下代码均来自实战项目 src/views/Element-plus-demo.vue。
1 2 3
| <el-button plain @click="dialogVisible = true">打开Dialog 对话框</el-button> <el-button @click="dialogVisible = false">Cancel</el-button> <el-button type="primary" @click="dialogVisible = false">Confirm</el-button>
|
| 属性 |
作用 |
type |
颜色风格:primary / success / info / warning / danger |
plain |
朴素按钮(浅色背景) |
2. Table 表格
1 2 3 4 5
| <el-table :data="tableData" stripe style="width: 100%" border="true"> <el-table-column prop="date" align="center" label="Date" width="180" /> <el-table-column prop="name" label="Name" align="center" width="180" /> <el-table-column prop="address" align="center" label="Address" /> </el-table>
|
1 2 3 4 5
| const tableData = [ { date: '2016-05-03', name: 'Tom', address: 'No. 189, Grove St, Los Angeles' }, { date: '2016-05-02', name: 'Tom', address: 'No. 189, Grove St, Los Angeles' }, ]
|
| 属性 |
写在哪 |
作用 |
data |
<el-table> |
表格数据源(数组) |
stripe |
<el-table> |
斑马纹(隔行变色) |
border |
<el-table> |
边框 |
prop |
<el-table-column> |
该列绑定 data 中的字段名 |
label |
<el-table-column> |
列标题 |
width |
<el-table-column> |
列宽度 |
align |
<el-table-column> |
单元格对齐:left/center/right |
自定义列内容(用作用域插槽 #default="scope",讲义案例中用到):
1 2 3 4 5 6 7 8 9 10 11
| <el-table-column label="头像" width="120" align="center"> <template #default="scope"> <img :src="scope.row.image" width="50"> </template> </el-table-column>
<el-table-column label="性别" align="center"> <template #default="scope"> {{ scope.row.gender == 1 ? '男' : '女' }} </template> </el-table-column>
|
📌 scope.row 表示当前行的数据对象,用 scope.row.字段名 取值。
1 2 3 4 5 6 7 8 9 10 11 12
| <el-pagination v-model:current-page="currentPage4" v-model:page-size="pageSize4" :page-sizes="[10, 20, 30, 40, 60, 100]" :size="size" :disabled="disabled" :background="background" layout="total, sizes, prev, pager, next, jumper" :total="400" @size-change="handleSizeChange" @current-change="handleCurrentChange" />
|
1 2 3 4 5 6 7 8
| const currentPage4 = ref(1) const pageSize4 = ref(100) const size = ref('default') const background = ref(false) const disabled = ref(false)
const handleSizeChange = (val) => { console.log(`${val} items per page`) } const handleCurrentChange = (val) => { console.log(`current page: ${val}`) }
|
| 属性/事件 |
说明 |
v-model:current-page |
当前页码(双向绑定) |
v-model:page-size |
每页条数(双向绑定) |
page-sizes |
可选每页条数下拉 |
size |
尺寸:large/default/small |
background |
按钮带背景色 |
disabled |
禁用分页 |
layout |
工具条布局,可选值:total、sizes、prev、pager、next、jumper |
total |
数据总条数 |
@size-change |
pageSize 改变时触发 |
@current-change |
currentPage 改变时触发 |
4. Dialog 对话框
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| <el-button plain @click="dialogVisible = true">打开Dialog 对话框</el-button>
<el-dialog v-model="dialogVisible" title="收货地址" width="60%" :before-close="handleClose" > <el-table :data="tableData" stripe style="width: 100%" border="true"> <el-table-column prop="date" align="center" label="Date" width="180" /> <el-table-column prop="name" label="Name" align="center" width="180" /> <el-table-column prop="address" align="center" label="Address" /> </el-table>
<template #footer> <div class="dialog-footer"> <el-button @click="dialogVisible = false">Cancel</el-button> <el-button type="primary" @click="dialogVisible = false">Confirm</el-button> </div> </template> </el-dialog>
|
1
| const dialogVisible = ref(false)
|
| 属性/插槽 |
说明 |
v-model |
绑定 boolean 变量,控制显示/隐藏 |
title |
对话框标题 |
width |
宽度(可用百分比 60% 或像素 500px) |
before-close |
关闭前回调(如需关闭确认) |
#footer |
底部插槽,放操作按钮 |
⚠️ 关键点:Dialog 的显示与隐藏通过 v-model 绑定的 boolean 值控制。对话框里可以放任意内容(表格、表单等)。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| <el-form :inline="true" :model="formInline" class="demo-form-inline"> <el-form-item label="姓名"> <el-input v-model="formInline.name" placeholder="请输入" clearable /> </el-form-item> <el-form-item label="性别"> <el-select v-model="formInline.gender" placeholder="请选择" clearable> <el-option label="男" value="1" /> <el-option label="女" value="2" /> </el-select> </el-form-item> <el-form-item label="出生日期"> <el-date-picker v-model="formInline.date" type="date" placeholder="请选择" clearable value-format="YYYY-MM-DD" /> </el-form-item> <el-form-item> <el-button type="primary" @click="onSubmit">Query</el-button> </el-form-item> </el-form>
|
1 2 3 4 5 6 7 8 9
| import { reactive } from 'vue' const formInline = reactive({ name: '', gender: '', date: '', }) const onSubmit = () => { console.log(formInline) }
|
| 属性 |
作用 |
:inline="true" |
行内表单(一行排列) |
:model |
绑定表单数据对象 |
clearable |
输入框/选择器可一键清空 |
value-format |
日期选择器返回值格式(如 YYYY-MM-DD) |
📌 实战细节:el-date-picker 加 value-format="YYYY-MM-DD" 后,formInline.date 拿到的就是 "2026-08-07" 这样的字符串,而不是 Date 对象,方便传给后端。
四、关键点:ref vs reactive(实战踩坑)
实战代码中表单数据用了 reactive,而讲义用的是 ref,这是值得注意的差异。
1. 两种写法对比
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| const formInline = ref({ user: '', region: '', date: '' })
console.log(formInline.value.user)
formInline.value = { user: '', region: '', date: '' }
import { reactive } from 'vue' const formInline = reactive({ name: '', gender: '', date: '' })
console.log(formInline.name)
Object.assign(formInline, { name: '', gender: '', date: '' })
|
2. ref vs reactive 对比表
| 对比项 |
ref |
reactive |
| 适用类型 |
任意值(基本类型 + 对象) |
仅对象/数组 |
| 访问方式 |
JS 中需 .value,模板自动解包 |
直接访问属性 |
| 模板中使用 |
{{ name }} |
{{ form.name }} |
| 整体替换 |
✅ x.value = {...} |
❌ 不能整体替换(会丢失响应式) |
| 解构 |
❌ 解构会失去响应式 |
❌ 解构会失去响应式(需 toRefs) |
| 推荐场景 |
单个值、需要整体替换 |
表单对象、一组相关数据 |
⚠️ 易错点:
reactive 对象不能直接整体赋值(formInline = {...} 会丢响应式),要用 Object.assign(formInline, {...}) 或逐个属性赋值。
ref 对象在 JS 中必须用 .value,模板里不用(自动解包)。
3. 模板中 v-model 绑定的差异
1 2 3 4 5
| <el-input v-model="formInline.user" />
<el-input v-model="formInline.name" />
|
模板里两者写法一样(都是 formInline.属性),区别在 JS 里访问和重置。
五、App.vue 引入组件
实战 App.vue:
1 2 3 4 5 6 7 8 9 10
| <script setup> import Elementdemo from './views/Element-plus-demo.vue' </script>
<template> <Elementdemo></Elementdemo> </template>
<style scoped> </style>
|
📌 .vue 文件是默认导出,import 时不加 {},名字可自定义(这里把 Element-plus-demo 改成了 Elementdemo,避免连字符影响变量名)。
六、常见问题 & 易混淆点
| 问题 |
答案 |
| ElementPlus 样式没生效? |
检查 main.js 是否 import 'element-plus/dist/index.css' |
| 组件显示英文怎么中文化? |
main.js 中 app.use(ElementPlus, { locale: zhCn }) |
| locale 路径报错怎么办? |
换路径:element-plus/es/locale/lang/zh-cn ↔ element-plus/dist/locale/zh-cn.mjs |
| Dialog 怎么控制显示隐藏? |
v-model 绑定一个 boolean 的 ref |
| Dialog 底部按钮怎么加? |
用 <template #footer> 插槽 |
| 表格某列要自定义内容(图片/判断)? |
用 <template #default="scope"> + scope.row.字段 |
| 表格隔行变色? |
<el-table stripe> |
| 日期选择器返回 Date 对象怎么转字符串? |
加 value-format="YYYY-MM-DD" |
ref 和 reactive 选哪个? |
单个值用 ref;表单对象用 reactive(访问不用 .value 更方便) |
reactive 对象能整体替换吗? |
❌ 不能,会丢响应式;用 Object.assign(obj, {...}) |
表单 :inline 和默认区别? |
inline 是一行排列;默认是每个表单项一行 |
el-pagination 怎么知道页码变了? |
监听 @current-change 和 @size-change 事件 |
七、组件属性速查表
Table 表格
| 标签 |
属性 |
作用 |
el-table |
data |
数据源 |
el-table |
stripe |
斑马纹 |
el-table |
border |
边框 |
el-table-column |
prop |
绑定字段 |
el-table-column |
label |
列标题 |
el-table-column |
width |
列宽 |
el-table-column |
align |
对齐方式 |
| 属性/事件 |
作用 |
v-model:current-page |
当前页 |
v-model:page-size |
每页条数 |
page-sizes |
可选条数数组 |
size |
尺寸 |
background |
背景色 |
disabled |
禁用 |
layout |
布局组合 |
total |
总条数 |
@size-change |
条数变化事件 |
@current-change |
页码变化事件 |
Dialog 对话框
| 属性/插槽 |
作用 |
v-model |
显隐控制(boolean) |
title |
标题 |
width |
宽度 |
before-close |
关闭前回调 |
#footer |
底部按钮插槽 |
| 标签 |
属性 |
作用 |
el-form |
:inline |
行内表单 |
el-form |
:model |
数据对象 |
el-form-item |
label |
标签文字 |
el-input |
v-model |
双向绑定 |
el-input |
clearable |
可清空 |
el-select |
v-model |
双向绑定 |
el-option |
label / value |
显示文字 / 实际值 |
el-date-picker |
type |
类型(date/datetime 等) |
el-date-picker |
value-format |
返回值格式 |
八、常用命令
1 2 3 4 5 6 7
| npm install element-plus@2.4.4 --save
npm run dev npm run build npm run preview
|
九、实战项目文件清单(vue-project03-ElementPlus)
1 2 3 4 5 6 7 8 9 10 11
| vue-project03-ElementPlus/ ├── index.html ├── package.json # 依赖:element-plus ^2.4.4, vue ^3.5.40 ├── vite.config.js └── src/ ├── main.js # ★ ElementPlus 引入 + 中文化配置 ├── App.vue # ★ 引入 Element-plus-demo.vue ├── views/ │ └── Element-plus-demo.vue # ★ 核心实战:表格/分页/对话框/表单 ├── components/ # 脚手架自带组件(未使用) └── assets/ # 样式文件
|
📌 复习建议:
- ElementPlus 不用背 API,记住”官网找 → 复制 → 改”的流程,组件属性速查表用来快速定位。
- 重点掌握 4 大组件:Table(含插槽自定义列)、Pagination(含事件)、Dialog(v-model 显隐)、Form(含各种输入控件)。
ref vs reactive 是 Vue 的核心易错点,理解两者在访问方式和整体替换上的差异。
- 动手试试:把表格数据改成从 axios 请求加载;给表单加一个”重置”按钮;改 Dialog 的 width 和 title。
- 后续可结合 day18 的”侧边栏 + 动态组件”,做一个左侧菜单切换不同 ElementPlus 页面的完整后台布局。