day19 前端Web实战-ElementPlus

实战总结: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. Button 按钮

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.字段名 取值。

3. Pagination 分页

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 工具条布局,可选值:totalsizesprevpagernextjumper
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 值控制。对话框里可以放任意内容(表格、表单等)。

5. Form 表单

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-pickervalue-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
// 写法一:ref(讲义风格)
const formInline = ref({
user: '', region: '', date: ''
})
// 访问需 .value
console.log(formInline.value.user)
// 重置需重新赋 .value
formInline.value = { user: '', region: '', date: '' }

// 写法二:reactive(实战风格)
import { reactive } from 'vue'
const formInline = reactive({
name: '', gender: '', date: ''
})
// 直接访问属性,不用 .value
console.log(formInline.name)
// 重置需逐个赋值或 Object.assign
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
<!-- ref 写法:v-model 绑定 .属性 -->
<el-input v-model="formInline.user" />

<!-- reactive 写法:v-model 直接绑定 .属性 -->
<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.jsapp.use(ElementPlus, { locale: zhCn })
locale 路径报错怎么办? 换路径:element-plus/es/locale/lang/zh-cnelement-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"
refreactive 选哪个? 单个值用 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 对齐方式

Pagination 分页

属性/事件 作用
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 底部按钮插槽

Form 表单

标签 属性 作用
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
# 安装 ElementPlus
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/ # 样式文件

📌 复习建议

  1. ElementPlus 不用背 API,记住”官网找 → 复制 → 改”的流程,组件属性速查表用来快速定位。
  2. 重点掌握 4 大组件:Table(含插槽自定义列)、Pagination(含事件)、Dialog(v-model 显隐)、Form(含各种输入控件)
  3. ref vs reactive 是 Vue 的核心易错点,理解两者在访问方式整体替换上的差异。
  4. 动手试试:把表格数据改成从 axios 请求加载;给表单加一个”重置”按钮;改 Dialog 的 width 和 title。
  5. 后续可结合 day18 的”侧边栏 + 动态组件”,做一个左侧菜单切换不同 ElementPlus 页面的完整后台布局。