WinddSnow

Element-Plus-Core-Components-Table-Form-Dialog-Message-Upload

字数统计: 5.3k阅读时长: 24 min
2026/07/29

第38课:Element Plus 核心组件——表格、表单、弹窗、消息提示、上传

Element Plus 提供了超过 80 个高质量组件,其中 表格(Table)表单(Form)弹窗(Dialog)消息提示(Message)上传(Upload) 是后台管理系统中最常用的五大核心组件。掌握它们的配置、数据绑定、事件处理和常见组合模式,能覆盖 80% 以上的后台页面需求。本节课将逐一拆解每个组件的关键属性和用法,并通过一个完整的 CRUD 用户管理页面 综合示例,展示如何将这些组件串联为可工作的业务模块。


1. 表格(Table)——数据展示与操作的核心

<el-table> 是 Element Plus 中功能最丰富的组件之一,支持排序、筛选、分页、固定列、合并单元格等高级特性。其基础用法是通过 data 属性绑定数组数据,内部用 <el-table-column> 定义列。

1.1 基础表格:数据绑定与列定义

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<template>
<el-table :data="tableData" style="width: 100%">
<el-table-column prop="date" label="日期" width="180" />
<el-table-column prop="name" label="姓名" width="180" />
<el-table-column prop="address" label="地址" />
</el-table>
</template>

<script setup>
import { ref } from 'vue'

const tableData = ref([
{ date: '2026-04-15', name: '张三', address: '北京市朝阳区' },
{ date: '2026-04-16', name: '李四', address: '上海市浦东新区' },
{ date: '2026-04-17', name: '王五', address: '广州市天河区' },
])
</script>
属性 类型 说明 默认值
data array 表格数据源,数组中的每个对象对应一行。 []
stripe boolean 是否显示斑马纹(隔行变色)。 false
border boolean 是否显示纵向边框。 false
height string/number 固定表头高度,超出则出现纵向滚动条(必须设置才能固定表头)。
max-height string/number 表格最大高度,内容超出时出现滚动条。

1.2 列属性:控制每列的渲染

<el-table-column> 通过 prop 指定数据字段,label 定义列头文字。支持自定义渲染和作用域插槽。

属性 说明
prop 对应 data 中对象的字段名。
label 列头显示文字。
width 固定列宽(像素),不设置则自动均分。
min-width 最小列宽,与 width 同时设置时以 min-width 为准。
fixed 固定列('left''right'),水平滚动时该列不动。
sortable 是否可排序(true / 'custom' 远程排序)。
align 对齐方式('left' / 'center' / 'right')。

自定义列渲染:使用默认插槽,scope.row 为当前行数据。

1
2
3
4
5
6
<el-table-column label="操作" width="180">
<template #default="scope">
<el-button size="small" @click="handleEdit(scope.row)">编辑</el-button>
<el-button size="small" type="danger" @click="handleDelete(scope.$index, scope.row)">删除</el-button>
</template>
</el-table-column>

scope.$index 为当前行索引(从 0 开始),scope.row 为当前行数据对象。

1.3 多选与序号

  • 多选列:添加 type="selection"<el-table-column>,表格上方会出现全选框。通过 @selection-change 事件获取已选行数组。
  • 序号列:添加 type="index",自动生成从 1 开始的序号。可通过 index 属性自定义起始序号。
1
2
3
4
5
<el-table :data="tableData" @selection-change="handleSelectionChange">
<el-table-column type="selection" width="55" />
<el-table-column type="index" label="序号" width="60" />
<!-- 其他数据列 -->
</el-table>

1.4 排序与筛选

排序:在列上设置 sortable 属性,可通过 sort-orders 自定义排序顺序(默认 ['ascending', 'descending', null])。若使用远程排序,设置 sortable="custom" 并监听 @sort-change 事件。

筛选:在列上设置 filters 属性和 filter-method 可实现前端筛选。filters{text, value} 数组。

1
2
3
4
5
6
7
8
9
<el-table-column
prop="tag"
label="标签"
:filters="[
{ text: '重要', value: '重要' },
{ text: '普通', value: '普通' },
]"
:filter-method="filterTag"
/>

2. 表单(Form)——数据收集与验证

<el-form> 提供表单布局、验证规则、数据绑定的统一解决方案。通常配合 <el-form-item> 包裹每个输入控件。

2.1 基础表单:数据模型与验证规则

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
<template>
<el-form :model="form" :rules="rules" ref="formRef" label-width="100px">
<el-form-item label="用户名" prop="username">
<el-input v-model="form.username" placeholder="请输入用户名" />
</el-form-item>
<el-form-item label="邮箱" prop="email">
<el-input v-model="form.email" placeholder="请输入邮箱" />
</el-form-item>
<el-form-item>
<el-button type="primary" @click="submitForm">提交</el-button>
<el-button @click="resetForm">重置</el-button>
</el-form-item>
</el-form>
</template>

<script setup>
import { reactive, ref } from 'vue'

const formRef = ref(null)
const form = reactive({
username: '',
email: '',
})

const rules = {
username: [
{ required: true, message: '请输入用户名', trigger: 'blur' },
{ min: 3, max: 10, message: '用户名长度在 3 到 10 个字符', trigger: 'blur' },
],
email: [
{ required: true, message: '请输入邮箱', trigger: 'blur' },
{ type: 'email', message: '请输入正确的邮箱格式', trigger: ['blur', 'change'] },
],
}

const submitForm = () => {
formRef.value.validate((valid) => {
if (valid) {
ElMessage.success('提交成功!')
} else {
ElMessage.error('请检查表单填写')
}
})
}

const resetForm = () => {
formRef.value.resetFields()
}
</script>

核心概念

  • :model 绑定表单数据对象(必须使用 reactiveref 包裹的响应式对象)。
  • :rules 绑定验证规则,每个 prop 对应一套规则数组。规则字段:required(必填)、message(提示)、trigger(触发时机:blur / change)、min / maxtype(数据类型,如 'email''url')。
  • ref="formRef" 用于在脚本中调用表单方法:validate() 验证整个表单,validateField() 验证单个字段,resetFields() 重置所有字段并清空验证错误。

2.2 内联表单与行内布局

通过设置 inline="true" 使表单域水平排列(常用于搜索栏)。此时 label-width 默认会被忽略。

1
2
3
4
5
6
7
8
<el-form :model="searchForm" inline>
<el-form-item label="关键字">
<el-input v-model="searchForm.keyword" placeholder="搜索..." />
</el-form-item>
<el-form-item>
<el-button type="primary" @click="handleSearch">搜索</el-button>
</el-form-item>
</el-form>

2.3 自定义验证规则

除了声明式规则,可以编写 validator 函数实现复杂逻辑。

1
2
3
4
5
6
7
8
9
10
11
const validatePassword = (rule, value, callback) => {
if (value === '') {
callback(new Error('请输入密码'))
} else if (!/(?=.*[a-z])(?=.*[A-Z])(?=.*\d)/.test(value)) {
callback(new Error('密码必须包含大小写字母和数字'))
} else {
callback()
}
}
// 在 rules 中使用:
{ validator: validatePassword, trigger: 'blur' }

3. 弹窗(Dialog)——模态交互窗口

<el-dialog> 用于在页面中弹出模态对话框,常用于表单编辑、详情展示、确认操作。

3.1 基本用法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
<template>
<el-button type="primary" @click="dialogVisible = true">打开弹窗</el-button>

<el-dialog v-model="dialogVisible" title="编辑用户" width="500px" :before-close="handleClose">
<el-form :model="editForm">
<el-form-item label="姓名">
<el-input v-model="editForm.name" />
</el-form-item>
</el-form>
<template #footer>
<el-button @click="dialogVisible = false">取消</el-button>
<el-button type="primary" @click="handleSave">保存</el-button>
</template>
</el-dialog>
</template>

<script setup>
import { ref, reactive } from 'vue'

const dialogVisible = ref(false)
const editForm = reactive({ name: '' })

const handleClose = (done) => {
// 可在关闭前进行确认
ElMessageBox.confirm('确定放弃未保存的修改?').then(() => done()).catch(() => {})
}

const handleSave = () => {
ElMessage.success('保存成功')
dialogVisible.value = false
}
</script>

关键属性

  • v-model 绑定显示/隐藏状态(boolean)。
  • title 弹窗标题。
  • width 弹窗宽度。
  • before-close 关闭前的回调,常用于二次确认。它接收一个 done 函数,调用 done() 才会真正关闭。
  • destroy-on-close 关闭时销毁弹窗内的组件(避免残留状态,推荐与表单配合使用)。

3.2 嵌套弹窗与全屏模式

设置 fullscreen 属性使弹窗全屏(适合移动端或复杂表单)。嵌套弹窗(弹窗中再开弹窗)只需在第一个弹窗内容中再放置一个 <el-dialog> 并管理各自的状态即可。


4. 消息提示(Message)与通知(Notification)

Element Plus 的消息提示是全局方法,无需在模板中嵌入组件,直接在 JavaScript 中调用。

4.1 ElMessage 基本用法

1
2
3
4
5
6
import { ElMessage } from 'element-plus'

ElMessage.success('操作成功')
ElMessage.error('操作失败')
ElMessage.warning('请注意')
ElMessage.info('这是一条信息')

所有方法返回一个 MessageHandle 对象,可手动调用 .close() 关闭。

全局配置:可在 el-config-providerapp.use 中设置消息的默认参数,如最大显示条数 max、持续时间 duration 等。也可以在调用时传入配置对象:

1
2
3
4
5
6
7
ElMessage({
type: 'success',
message: '这是一条自定义消息',
duration: 3000,
showClose: true,
center: true,
})

4.2 ElMessageBox 确认框

用于用户确认操作(如删除)。

1
2
3
4
5
6
7
8
9
import { ElMessageBox } from 'element-plus'

ElMessageBox.confirm('确定永久删除该用户?', '警告', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning',
})
.then(() => { ElMessage.success('已删除') })
.catch(() => { ElMessage.info('已取消') })

也支持 prompt(输入框)和 alert(警告框)。

4.3 ElNotification 通知

Message 类似,但出现在屏幕右上角,支持更复杂的标题和内容,可自定义关闭按钮和持续时间。

1
2
3
4
5
6
7
8
import { ElNotification } from 'element-plus'

ElNotification({
title: '新消息',
message: '有 3 条待处理任务',
type: 'info',
duration: 5000,
})

5. 上传(Upload)——文件与图片上传

<el-upload> 封装了文件上传的 UI 和基础逻辑,支持图片预览、拖拽、多文件、限制格式与大小。

5.1 基础用法:手动上传

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
<template>
<el-upload
ref="uploadRef"
action="/api/upload"
:auto-upload="false"
:on-change="handleFileChange"
:on-remove="handleRemove"
:limit="3"
accept="image/png,image/jpeg"
list-type="picture-card"
>
<el-icon><Plus /></el-icon>
</el-upload>
<el-button type="primary" @click="submitUpload" style="margin-top: 12px;">上传到服务器</el-button>
</template>

<script setup>
import { ref } from 'vue'
import { ElMessage } from 'element-plus'
import { Plus } from '@element-plus/icons-vue'

const uploadRef = ref(null)
const fileList = ref([])

const handleFileChange = (file, fileList) => {
// file 为当前变更的文件,fileList 为当前所有文件列表
}

const handleRemove = (file, fileList) => {
// 移除文件时触发
}

const submitUpload = () => {
uploadRef.value.submit() // 手动触发表单提交
}
</script>

核心属性

属性 说明 默认值
action 上传的服务器地址(必填)。
auto-upload 是否选取文件后立即自动上传。 true
limit 最大允许上传个数。
accept 限制文件类型(MIME 类型,如 image/*)。
list-type 文件列表展示类型:'text' / 'picture' / 'picture-card' 'text'
before-upload 上传前的钩子函数,可对文件进行大小、类型校验,返回 false 阻止上传。
on-success 上传成功的回调,参数为 (response, file, fileList)
on-error 上传失败的回调。
on-change 文件状态改变时的钩子(添加、删除、上传成功等均触发)。

上传前校验示例

1
2
3
4
5
6
7
8
9
10
11
12
13
const beforeUpload = (file) => {
const isImage = file.type.startsWith('image/')
const isLt2M = file.size / 1024 / 1024 < 2
if (!isImage) {
ElMessage.error('只能上传图片文件!')
return false
}
if (!isLt2M) {
ElMessage.error('图片大小不能超过 2MB!')
return false
}
return true
}

5.2 配合表单提交

通常上传组件单独提交文件,然后表单提交时携带返回的 URL。使用 on-success 获取服务器返回的文件地址,存入表单数据模型。


6. 综合实战:用户管理 CRUD 页面

下面将表格、表单、弹窗、消息提示、上传组合成一个完整的用户管理页面,支持查看列表、新增/编辑用户(弹窗表单)、删除确认、头像上传。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
<template>
<div class="user-manage">
<!-- 操作栏 -->
<div style="margin-bottom: 16px;">
<el-button type="primary" @click="openDialog('add')">新增用户</el-button>
</div>

<!-- 用户表格 -->
<el-table :data="users" border stripe style="width: 100%">
<el-table-column type="index" label="序号" width="60" />
<el-table-column prop="name" label="姓名" />
<el-table-column prop="email" label="邮箱" />
<el-table-column label="头像" width="100">
<template #default="{ row }">
<el-avatar :src="row.avatar" :size="40" />
</template>
</el-table-column>
<el-table-column label="操作" width="180">
<template #default="{ row, $index }">
<el-button size="small" @click="openDialog('edit', row)">编辑</el-button>
<el-button size="small" type="danger" @click="handleDelete($index)">删除</el-button>
</template>
</el-table-column>
</el-table>

<!-- 新增/编辑弹窗 -->
<el-dialog v-model="dialogVisible" :title="dialogTitle" width="500px" destroy-on-close>
<el-form :model="form" :rules="rules" ref="formRef" label-width="80px">
<el-form-item label="姓名" prop="name">
<el-input v-model="form.name" placeholder="请输入姓名" />
</el-form-item>
<el-form-item label="邮箱" prop="email">
<el-input v-model="form.email" placeholder="请输入邮箱" />
</el-form-item>
<el-form-item label="头像">
<el-upload
ref="uploadRef"
action="https://run.mocky.io/v3/9d059bf9-4660-45f2-925d-ce80ad6c4d15"
:auto-upload="false"
:limit="1"
list-type="picture-card"
:on-change="handleAvatarChange"
:on-remove="() => form.avatar = ''"
>
<el-icon><Plus /></el-icon>
</el-upload>
</el-form-item>
</el-form>
<template #footer>
<el-button @click="dialogVisible = false">取消</el-button>
<el-button type="primary" @click="handleSave">保存</el-button>
</template>
</el-dialog>
</div>
</template>

<script setup>
import { ref, reactive, computed, nextTick } from 'vue'
import { ElMessage, ElMessageBox } from 'element-plus'
import { Plus } from '@element-plus/icons-vue'

const users = ref([
{ name: '张三', email: 'zhangsan@example.com', avatar: '' },
{ name: '李四', email: 'lisi@example.com', avatar: '' },
])

const dialogVisible = ref(false)
const dialogType = ref('add') // 'add' | 'edit'
const editIndex = ref(-1)
const formRef = ref(null)
const form = reactive({ name: '', email: '', avatar: '' })

const rules = {
name: [{ required: true, message: '请输入姓名', trigger: 'blur' }],
email: [
{ required: true, message: '请输入邮箱', trigger: 'blur' },
{ type: 'email', message: '邮箱格式不正确', trigger: ['blur', 'change'] },
],
}

const dialogTitle = computed(() => dialogType.value === 'add' ? '新增用户' : '编辑用户')

const openDialog = (type, row) => {
dialogType.value = type
if (type === 'add') {
// 重置表单
form.name = ''
form.email = ''
form.avatar = ''
editIndex.value = -1
} else {
// 编辑:拷贝行数据
form.name = row.name
form.email = row.email
form.avatar = row.avatar
editIndex.value = users.value.indexOf(row)
}
dialogVisible.value = true
// 重置表单校验状态
nextTick(() => formRef.value?.clearValidate())
}

const handleAvatarChange = (uploadFile) => {
// 将文件转换为临时 URL 用于预览,实际上传后应使用服务器返回的 URL
form.avatar = URL.createObjectURL(uploadFile.raw)
}

const handleSave = () => {
formRef.value.validate((valid) => {
if (!valid) return
if (dialogType.value === 'add') {
users.value.push({ ...form })
ElMessage.success('添加成功')
} else {
users.value[editIndex.value] = { ...form }
ElMessage.success('修改成功')
}
dialogVisible.value = false
})
}

const handleDelete = (index) => {
ElMessageBox.confirm('确定删除该用户?', '警告', { type: 'warning' })
.then(() => {
users.value.splice(index, 1)
ElMessage.success('已删除')
})
.catch(() => {})
}
</script>

<style scoped>
.user-manage {
padding: 20px;
}
</style>

组件协同说明

  • 表格负责数据展示,操作列触发弹窗和删除。
  • 弹窗内嵌表单和上传组件,根据 dialogType 动态切换新增/编辑逻辑。
  • 删除使用 ElMessageBox.confirm 进行二次确认。
  • 上传组件采用手动上传模式(auto-upload="false"),选取文件后仅做预览,保存时才提交整个表单。生产环境中应在 handleSave 中调用 uploadRef.value.submit() 先上传文件,拿到 URL 后再提交表单。

课后练习

一、概念自测(选择题 / 填空题)

  1. (单选)el-table 中,要固定某列在左侧不随水平滚动,应设置哪个属性?
    A. sticky
    B. fixed="left"
    C. position="left"
    D. lock

  2. (单选) 以下关于 el-form 验证规则 trigger 的描述,正确的是?
    A. trigger: 'blur' 表示在失去焦点时验证。
    B. trigger: 'change' 仅对选择框有效。
    C. trigger 只能指定一个值。
    D. 若不设置 trigger,表单不会进行任何验证。

  3. (填空) 要手动触发 el-upload 的上传,需要先获取组件的引用,然后调用其 ______ 方法。

  4. (多选) 以下哪些是 ElMessage 支持的类型?
    A. success
    B. error
    C. warning
    D. info

二、AI 编程任务:编写面向 AI 的提示词

场景:你需要实现一个商品管理页面,包含以下功能:

  • 使用 el-table 展示商品列表,列包括:商品图片(缩略图)、商品名称、价格、库存状态(自定义列:使用 el-tag 显示“有货”绿色或“无货”红色)、操作列(编辑/删除按钮)。
  • 表格上方有一个搜索栏(el-form 内联布局),包含关键字输入框和搜索按钮。
  • 点击“新增商品”或“编辑”按钮,弹出 el-dialog,内部是一个 el-form,包含商品名称、价格、库存数量、商品图片上传(el-upload,限制单张图片、格式为 jpg/png)。
  • 删除商品时使用 ElMessageBox.confirm 进行二次确认,确认后 ElMessage.success 提示删除成功。
  • 所有组件通过自动按需引入方式(unplugin-vue-components)可用,无需手动导入。

任务要求:请写出一段完整的中文提示词,发送给 AI,使其生成一个完整的 Vue 3 + Element Plus 单文件组件(.vue)。提示词中需明确指定组件的结构、数据流、验证规则和交互行为。


课后练习答案

一、概念自测答案

  1. B

    • 解析:fixed="left"fixed="right" 用于固定列在左侧或右侧,水平滚动时保持不动。
  2. A

    • 解析:trigger: 'blur' 在输入框失去焦点时触发验证。trigger 可以是一个字符串或数组(['blur', 'change'])。若未设置 trigger,默认为 'change'(除 el-input 外部分控件默认为 'blur')。
  3. submit

    • 解析:通过 ref 获取 <el-upload> 组件实例,调用 submit() 方法手动触发上传。
  4. A、B、C、D

    • 解析:ElMessage.success().error().warning().info() 均为 Element Plus 提供的快捷方法。

二、AI 编程任务参考答案(提示词示例)

示例提示词
“请生成一个 Vue 3 + Element Plus 的商品管理页面组件。要求:

  • 使用 <script setup> 语法,组件已配置 unplugin-vue-components 自动按需引入 Element Plus 组件,无需手动导入。
  • 表格 el-table 绑定 products 数组数据,包含列:图片(用 el-image 缩略图,fit="cover",宽度 60px)、名称、价格(保留两位小数)、库存状态(自定义列模板:<el-tag>stock > 0 时 type=”success” 文本“有货”,否则 type=”danger” 文本“无货”)、操作列(el-button 编辑和删除)。
  • 表格上方内联表单 el-form inline,包含一个 el-input 搜索框和一个 el-button 搜索按钮(可暂时仅 console.log 搜索关键字)。
  • 新增/编辑弹窗 el-dialog,通过 dialogVisible 控制,标题根据 isEdit 变量切换“新增商品”或“编辑商品”。弹窗内 el-form:model="form",验证规则 rules:名称必填、价格必填且为正数、库存为非负整数。表单包含:名称 el-input、价格 el-input-number:min="0" :precision="2")、库存 el-input-number:min="0" :step="1")、图片上传 el-uploadlist-type="picture-card":limit="1"accept="image/jpeg,image/png",设置 auto-upload="false"on-change 时将文件转为临时 URL 存入 form.image)。保存时调用 formRef.validate(),通过后新增或更新 products 数组,并用 ElMessage.success 提示。
  • 删除按钮调用 ElMessageBox.confirm,确认后从数组中移除并用 ElMessage.success 提示。
  • 代码完整可运行,包含必要的 import { ref, reactive, computed, nextTick } from 'vue',并假设 ElMessage 等已全局可用。直接输出 .vue 文件内容。”
CATALOG
  1. 1. 第38课:Element Plus 核心组件——表格、表单、弹窗、消息提示、上传
    1. 1.1. 1. 表格(Table)——数据展示与操作的核心
      1. 1.1.1. 1.1 基础表格:数据绑定与列定义
      2. 1.1.2. 1.2 列属性:控制每列的渲染
      3. 1.1.3. 1.3 多选与序号
      4. 1.1.4. 1.4 排序与筛选
    2. 1.2. 2. 表单(Form)——数据收集与验证
      1. 1.2.1. 2.1 基础表单:数据模型与验证规则
      2. 1.2.2. 2.2 内联表单与行内布局
      3. 1.2.3. 2.3 自定义验证规则
    3. 1.3. 3. 弹窗(Dialog)——模态交互窗口
      1. 1.3.1. 3.1 基本用法
      2. 1.3.2. 3.2 嵌套弹窗与全屏模式
    4. 1.4. 4. 消息提示(Message)与通知(Notification)
      1. 1.4.1. 4.1 ElMessage 基本用法
      2. 1.4.2. 4.2 ElMessageBox 确认框
      3. 1.4.3. 4.3 ElNotification 通知
    5. 1.5. 5. 上传(Upload)——文件与图片上传
      1. 1.5.1. 5.1 基础用法:手动上传
      2. 1.5.2. 5.2 配合表单提交
    6. 1.6. 6. 综合实战:用户管理 CRUD 页面
    7. 1.7. 课后练习
      1. 1.7.1. 一、概念自测(选择题 / 填空题)
      2. 1.7.2. 二、AI 编程任务:编写面向 AI 的提示词
    8. 1.8. 课后练习答案
      1. 1.8.1. 一、概念自测答案
      2. 1.8.2. 二、AI 编程任务参考答案(提示词示例)