目录
- 前言
- [一、Element Plus 是什么?](#一、Element Plus 是什么?)
-
- [1.1 UI 组件库的作用](#1.1 UI 组件库的作用)
- [1.2 为什么选择 Element Plus?](#1.2 为什么选择 Element Plus?)
- 二、安装与配置
-
- [2.1 安装](#2.1 安装)
- [2.2 完整引入](#2.2 完整引入)
- [2.3 按需引入(推荐)](#2.3 按需引入(推荐))
- 三、表格组件
-
- [3.1 基础表格](#3.1 基础表格)
- [3.2 自定义列内容](#3.2 自定义列内容)
- [3.3 加载状态](#3.3 加载状态)
- 四、分页组件
-
- [4.1 基础分页](#4.1 基础分页)
- [4.2 后端分页(真实场景)](#4.2 后端分页(真实场景))
- 五、搜索与删除
-
- [5.1 搜索功能](#5.1 搜索功能)
- [5.2 删除功能](#5.2 删除功能)
- [5.3 批量删除](#5.3 批量删除)
- 六、新增与修改
-
- [6.1 对话框组件](#6.1 对话框组件)
- [6.2 表单组件](#6.2 表单组件)
- [6.3 表单回显与重置](#6.3 表单回显与重置)
- 七、子组件通信
-
- [7.1 定义子组件](#7.1 定义子组件)
- [7.2 父组件使用子组件](#7.2 父组件使用子组件)
- [7.3 父子组件通信总结](#7.3 父子组件通信总结)
- 八、完整案例:学生管理页面
- 总结
前言
在与后端交互:axios与请求封装中,我们掌握了前端与后端 API 交互的方式。现在数据能获取到了,但如何优雅地展示和管理这些数据呢?
直接用原生 HTML 标签(table、form)可以实现功能,但样式简陋、交互生硬,还需要自己写大量 CSS 和 JavaScript。在实际开发中,我们通常使用 UI 组件库 来快速构建美观、交互友好的界面。
Element Plus 是 Vue3 生态中最成熟的 UI 组件库,提供了表格、表单、对话框、分页等常用组件,开箱即用。
本文将通过一个学生管理系统案例,讲解 Element Plus 的核心组件和实战技巧,包括表格、分页、搜索、增删改、表单校验、子组件通信等。
一、Element Plus 是什么?
1.1 UI 组件库的作用
如果把开发比作装修:
- 原生 HTML/CSS 是自己买材料、自己设计、自己施工
- UI 组件库 是精装修套餐------样式美观、交互完善、开箱即用
组件库提供的典型组件:
| 类别 | 组件 | 作用 |
|---|---|---|
| 基础 | Button、Icon、Link | 按钮、图标、链接 |
| 表单 | Input、Select、Checkbox、Radio、Switch | 各类输入控件 |
| 数据 | Table、Pagination、Tree、Tag | 数据展示 |
| 反馈 | Message、Dialog、Notification、Loading | 提示反馈 |
| 导航 | Menu、Tabs、Breadcrumb | 页面导航 |
| 布局 | Container、Layout、Grid | 页面布局 |
1.2 为什么选择 Element Plus?
| 优势 | 说明 |
|---|---|
| Vue3 原生支持 | 基于 Vue3 开发,完美支持组合式 API |
| 组件丰富 | 60+ 组件,覆盖绝大多数场景 |
| 文档完善 | 中文文档详细,示例丰富 |
| 生态成熟 | 社区活跃,问题容易找到解决方案 |
| 企业级 | 饿了么团队开发,经受过大规模项目验证 |
类比 Java:Element Plus 类似于 Java 的前端 UI 框架,如 Apache Wicket 或 JSF 组件库,但更现代化。
二、安装与配置
2.1 安装
bash
npm install element-plus
2.2 完整引入
在 main.ts 中引入 Element Plus 及其样式:
typescript
import { createApp } from 'vue'
import ElementPlus from 'element-plus'
import 'element-plus/dist/index.css'
import App from './App.vue'
const app = createApp(App)
app.use(ElementPlus)
app.mount('#app')
2.3 按需引入(推荐)
完整引入会导致打包体积较大。推荐使用按需引入,只打包用到的组件。
安装自动导入插件:
bash
npm install -D unplugin-vue-components unplugin-auto-import
配置 vite.config.ts:
typescript
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
import AutoImport from 'unplugin-auto-import/vite'
import Components from 'unplugin-vue-components/vite'
import { ElementPlusResolver } from 'unplugin-vue-components/resolvers'
export default defineConfig({
plugins: [
vue(),
AutoImport({
resolvers: [ElementPlusResolver()]
}),
Components({
resolvers: [ElementPlusResolver()]
})
]
})
配置后,无需手动 import,直接使用组件即可:
vue
<template>
<!-- 自动导入,无需 import -->
<el-button type="primary">按钮</el-button>
</template>
三、表格组件
表格是后台管理系统最常用的组件。Element Plus 的 el-table 功能强大,支持排序、筛选、固定列、自定义列等。
3.1 基础表格
vue
<script setup lang="ts">
import { ref } from 'vue'
interface Student {
id: number
name: string
sex: string
age: number
}
const students = ref<Student[]>([
{ id: 1, name: '张三', sex: '男', age: 18 },
{ id: 2, name: '李四', sex: '女', age: 19 },
{ id: 3, name: '王五', sex: '男', age: 20 }
])
</script>
<template>
<el-table :data="students" border stripe style="width: 100%">
<el-table-column prop="id" label="编号" width="100" />
<el-table-column prop="name" label="姓名" />
<el-table-column prop="sex" label="性别" />
<el-table-column prop="age" label="年龄" />
</el-table>
</template>
| 属性 | 说明 |
|---|---|
:data |
表格数据(数组) |
border |
显示边框 |
stripe |
斑马纹 |
prop |
列对应的字段名 |
label |
列标题 |
width |
列宽度 |
3.2 自定义列内容
有时需要在列中显示复杂内容(如按钮、格式化文本):
vue
<template>
<el-table :data="students" border stripe>
<el-table-column prop="id" label="编号" width="100" />
<el-table-column prop="name" label="姓名">
<!-- 自定义列:通过 #default 获取当前行数据 -->
<template #default="{ row }">
<span :style="{ color: row.sex === '女' ? 'pink' : 'blue' }">
{{ row.name }}
</span>
</template>
</el-table-column>
<el-table-column prop="sex" label="性别" />
<el-table-column label="操作">
<template #default="{ row }">
<el-button type="primary" size="small" @click="handleEdit(row)">编辑</el-button>
<el-button type="danger" size="small" @click="handleDelete(row.id)">删除</el-button>
</template>
</el-table-column>
</el-table>
</template>
<script setup lang="ts">
function handleEdit(row: Student) {
console.log('编辑:', row)
}
function handleDelete(id: number) {
console.log('删除:', id)
}
</script>
重要 :
#default="{ row }"是插槽语法,row是当前行的数据对象。
3.3 加载状态
从后端获取数据时,显示加载状态:
vue
<script setup lang="ts">
import { ref, onMounted } from 'vue'
import request from '@/api/request'
const students = ref<Student[]>([])
const loading = ref(false)
async function getStudents() {
loading.value = true
try {
const data = await request.get<Student[]>('/api/students')
students.value = data
} finally {
loading.value = false
}
}
onMounted(() => {
getStudents()
})
</script>
<template>
<el-table :data="students" border stripe v-loading="loading">
<el-table-column prop="id" label="编号" />
<el-table-column prop="name" label="姓名" />
<!-- ... -->
</el-table>
</template>
四、分页组件
数据量大时,需要分页展示。Element Plus 的 el-pagination 与表格配合使用。
4.1 基础分页
vue
<script setup lang="ts">
import { ref, computed } from 'vue'
const allStudents = ref<Student[]>([
// 假设有 100 条数据...
])
const currentPage = ref(1)
const pageSize = ref(10)
// 当前页数据
const currentPageData = computed(() => {
const start = (currentPage.value - 1) * pageSize.value
const end = start + pageSize.value
return allStudents.value.slice(start, end)
})
function handlePageChange(page: number) {
currentPage.value = page
}
function handleSizeChange(size: number) {
pageSize.value = size
currentPage.value = 1 // 切换每页条数时,重置到第一页
}
</script>
<template>
<el-table :data="currentPageData" border stripe>
<!-- 列定义... -->
</el-table>
<el-pagination
v-model:current-page="currentPage"
v-model:page-size="pageSize"
:page-sizes="[10, 20, 50, 100]"
:total="allStudents.length"
layout="total, sizes, prev, pager, next, jumper"
@size-change="handleSizeChange"
@current-change="handlePageChange"
/>
</template>
| 属性/事件 | 说明 |
|---|---|
v-model:current-page |
当前页码 |
v-model:page-size |
每页条数 |
:page-sizes |
每页条数选项 |
:total |
总记录数 |
layout |
分页布局元素 |
@size-change |
每页条数改变事件 |
@current-change |
页码改变事件 |
4.2 后端分页(真实场景)
实际项目中,分页通常由后端实现,前端只传递分页参数:
vue
<script setup lang="ts">
import { ref, onMounted } from 'vue'
import { useRequest } from 'vue-request'
import request from '@/api/request'
interface PageResult<T> {
list: T[]
total: number
}
const queryParams = ref({
name: '',
page: 1,
size: 10
})
const { data, total, loading, run } = useRequest<PageResult<Student>>(
() => request.get('/api/students/page', { params: queryParams.value }),
{
defaultParams: [queryParams.value],
pagination: {
currentKey: 'page',
pageSizeKey: 'size',
totalKey: 'data.total'
}
}
)
function handlePageChange(page: number) {
queryParams.value.page = page
run(queryParams.value)
}
function handleSizeChange(size: number) {
queryParams.value.size = size
queryParams.value.page = 1
run(queryParams.value)
}
</script>
<template>
<el-table :data="data?.list || []" border stripe v-loading="loading">
<el-table-column prop="id" label="编号" />
<el-table-column prop="name" label="姓名" />
<!-- ... -->
</el-table>
<el-pagination
v-model:current-page="queryParams.page"
v-model:page-size="queryParams.size"
:page-sizes="[10, 20, 50]"
:total="total"
layout="total, sizes, prev, pager, next"
@size-change="handleSizeChange"
@current-change="handlePageChange"
/>
</template>
五、搜索与删除
5.1 搜索功能
vue
<script setup lang="ts">
import { ref } from 'vue'
const queryParams = ref({
name: '',
sex: '',
ageRange: ''
})
const { data, loading, run } = useRequest(
() => request.get('/api/students/page', { params: queryParams.value })
)
function handleSearch() {
queryParams.value.page = 1 // 搜索时重置到第一页
run()
}
</script>
<template>
<div class="search-bar">
<el-input
v-model="queryParams.name"
placeholder="姓名"
style="width: 150px"
clearable
/>
<el-select
v-model="queryParams.sex"
placeholder="性别"
style="width: 100px"
clearable
>
<el-option label="男" value="男" />
<el-option label="女" value="女" />
</el-select>
<el-select
v-model="queryParams.ageRange"
placeholder="年龄"
style="width: 120px"
clearable
>
<el-option label="18岁以下" value="0,18" />
<el-option label="18-25岁" value="18,25" />
<el-option label="25岁以上" value="25,100" />
</el-select>
<el-button type="primary" @click="handleSearch">搜索</el-button>
</div>
<el-table :data="data?.list || []" border stripe v-loading="loading">
<!-- 列定义... -->
</el-table>
</template>
<style scoped>
.search-bar {
margin-bottom: 16px;
display: flex;
gap: 8px;
}
</style>
5.2 删除功能
使用 ElMessageBox 确认删除:
vue
<script setup lang="ts">
import { ElMessage, ElMessageBox } from 'element-plus'
async function handleDelete(id: number) {
try {
// 确认框
await ElMessageBox.confirm('确认删除该学生?', '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
})
// 调用删除接口
await request.delete(`/api/students/${id}`)
// 提示成功
ElMessage.success('删除成功')
// 刷新列表
run()
} catch (error) {
// 用户点击取消,不做处理
if (error === 'cancel') return
ElMessage.error('删除失败')
}
}
</script>
5.3 批量删除
vue
<script setup lang="ts">
import { ref } from 'vue'
const selectedIds = ref<number[]>([])
// 表格选择变化事件
function handleSelectionChange(selection: Student[]) {
selectedIds.value = selection.map(s => s.id)
}
async function handleBatchDelete() {
if (selectedIds.value.length === 0) {
ElMessage.warning('请先选择要删除的学生')
return
}
try {
await ElMessageBox.confirm(`确认删除选中的 ${selectedIds.value.length} 名学生?`, '提示')
await request.delete('/api/students', { data: selectedIds.value })
ElMessage.success('删除成功')
selectedIds.value = []
run()
} catch (error) {
if (error !== 'cancel') {
ElMessage.error('删除失败')
}
}
}
</script>
<template>
<el-button type="danger" @click="handleBatchDelete">批量删除</el-button>
<el-table
:data="data?.list || []"
border
stripe
@selection-change="handleSelectionChange"
>
<!-- 多选列 -->
<el-table-column type="selection" width="55" />
<el-table-column prop="id" label="编号" />
<!-- ... -->
</el-table>
</template>
六、新增与修改
新增和修改通常使用对话框(Dialog)+ 表单(Form)实现。
6.1 对话框组件
vue
<script setup lang="ts">
import { ref } from 'vue'
const dialogVisible = ref(false)
const dialogTitle = ref('新增学生')
// 打开新增对话框
function handleAdd() {
dialogTitle.value = '新增学生'
dialogVisible.value = true
}
// 打开编辑对话框
function handleEdit(row: Student) {
dialogTitle.value = '编辑学生'
// 回填表单数据...
dialogVisible.value = true
}
</script>
<template>
<el-button type="primary" @click="handleAdd">新增学生</el-button>
<el-dialog
v-model="dialogVisible"
:title="dialogTitle"
width="500px"
>
<!-- 表单内容 -->
<span>这里是表单...</span>
<template #footer>
<el-button @click="dialogVisible = false">取消</el-button>
<el-button type="primary" @click="handleSubmit">确定</el-button>
</template>
</el-dialog>
</template>
6.2 表单组件
vue
<script setup lang="ts">
import { ref, reactive } from 'vue'
interface StudentForm {
id?: number
name: string
sex: string
age: number
}
const form = reactive<StudentForm>({
name: '',
sex: '男',
age: 18
})
const formRef = ref()
const rules = {
name: [
{ required: true, message: '请输入姓名', trigger: 'blur' },
{ min: 2, max: 10, message: '长度在 2 到 10 个字符', trigger: 'blur' }
],
sex: [
{ required: true, message: '请选择性别', trigger: 'change' }
],
age: [
{ required: true, message: '请输入年龄', trigger: 'blur' },
{ type: 'number', min: 1, max: 150, message: '年龄在 1 到 150 之间', trigger: 'blur' }
]
}
async function handleSubmit() {
try {
// 表单校验
await formRef.value.validate()
// 提交数据
if (form.id) {
await request.put(`/api/students/${form.id}`, form)
ElMessage.success('修改成功')
} else {
await request.post('/api/students', form)
ElMessage.success('新增成功')
}
dialogVisible.value = false
run() // 刷新列表
} catch (error) {
// 校验失败,不做处理
}
}
</script>
<template>
<el-dialog v-model="dialogVisible" :title="dialogTitle" width="500px">
<el-form
ref="formRef"
:model="form"
:rules="rules"
label-width="80px"
>
<el-form-item label="姓名" prop="name">
<el-input v-model="form.name" />
</el-form-item>
<el-form-item label="性别" prop="sex">
<el-radio-group v-model="form.sex">
<el-radio value="男">男</el-radio>
<el-radio value="女">女</el-radio>
</el-radio-group>
</el-form-item>
<el-form-item label="年龄" prop="age">
<el-input-number v-model="form.age" :min="1" :max="150" />
</el-form-item>
</el-form>
<template #footer>
<el-button @click="dialogVisible = false">取消</el-button>
<el-button type="primary" @click="handleSubmit">确定</el-button>
</template>
</el-dialog>
</template>
| Element Plus | 说明 | 类比 Java |
|---|---|---|
:model |
表单数据对象 | JavaBean |
:rules |
校验规则 | @NotNull、@Size 等注解 |
prop |
字段名(与 rules 对应) | 属性名 |
trigger |
触发时机 | - |
validate() |
执行校验 | 手动校验 |
6.3 表单回显与重置
编辑时需要回显数据,新增/编辑后需要重置表单:
vue
<script setup lang="ts">
import { ref, reactive, nextTick } from 'vue'
const form = reactive<StudentForm>({
name: '',
sex: '男',
age: 18
})
const formRef = ref()
// 打开新增对话框
function handleAdd() {
dialogTitle.value = '新增学生'
resetForm()
dialogVisible.value = true
}
// 打开编辑对话框
async function handleEdit(row: Student) {
dialogTitle.value = '编辑学生'
// 先打开对话框,再回填数据(避免校验立即触发)
dialogVisible.value = true
// 等待 DOM 更新后再回填
await nextTick()
Object.assign(form, row)
}
// 重置表单
function resetForm() {
formRef.value?.resetFields()
// 或者手动重置
Object.assign(form, {
name: '',
sex: '男',
age: 18
})
}
// 提交成功后
async function handleSubmit() {
// ...提交逻辑...
dialogVisible.value = false
resetForm() // 重置表单
run()
}
</script>
七、子组件通信
当对话框表单逻辑复杂时,建议将表单抽取为子组件。
7.1 定义子组件
新建 src/components/StudentForm.vue:
vue
<script setup lang="ts">
import { ref, reactive, watch } from 'vue'
import type { FormInstance } from 'element-plus'
interface StudentForm {
id?: number
name: string
sex: string
age: number
}
// 接收父组件传递的属性
const props = defineProps<{
modelValue: boolean // 对话框显示状态
student?: StudentForm // 编辑时传入的学生数据
}>()
// 定义事件
const emit = defineEmits<{
'update:modelValue': [value: boolean]
'success': []
}>()
const formRef = ref<FormInstance>()
const form = reactive<StudentForm>({
name: '',
sex: '男',
age: 18
})
const rules = {
name: [{ required: true, message: '请输入姓名', trigger: 'blur' }],
sex: [{ required: true, message: '请选择性别', trigger: 'change' }],
age: [{ required: true, message: '请输入年龄', trigger: 'blur' }]
}
// 监听 student 变化,回填表单
watch(
() => props.student,
(newStudent) => {
if (newStudent) {
Object.assign(form, newStudent)
} else {
resetForm()
}
}
)
function resetForm() {
formRef.value?.resetFields()
}
async function handleSubmit() {
try {
await formRef.value?.validate()
if (form.id) {
await request.put(`/api/students/${form.id}`, form)
ElMessage.success('修改成功')
} else {
await request.post('/api/students', form)
ElMessage.success('新增成功')
}
emit('update:modelValue', false)
emit('success')
} catch (error) {
// 校验失败
}
}
function handleCancel() {
emit('update:modelValue', false)
resetForm()
}
</script>
<template>
<el-dialog
:model-value="modelValue"
:title="student ? '编辑学生' : '新增学生'"
width="500px"
@close="handleCancel"
>
<el-form ref="formRef" :model="form" :rules="rules" label-width="80px">
<el-form-item label="姓名" prop="name">
<el-input v-model="form.name" />
</el-form-item>
<el-form-item label="性别" prop="sex">
<el-radio-group v-model="form.sex">
<el-radio value="男">男</el-radio>
<el-radio value="女">女</el-radio>
</el-radio-group>
</el-form-item>
<el-form-item label="年龄" prop="age">
<el-input-number v-model="form.age" :min="1" :max="150" />
</el-form-item>
</el-form>
<template #footer>
<el-button @click="handleCancel">取消</el-button>
<el-button type="primary" @click="handleSubmit">确定</el-button>
</template>
</el-dialog>
</template>
7.2 父组件使用子组件
vue
<script setup lang="ts">
import { ref } from 'vue'
import StudentForm from '@/components/StudentForm.vue'
const dialogVisible = ref(false)
const currentStudent = ref<Student | undefined>()
// 新增
function handleAdd() {
currentStudent.value = undefined
dialogVisible.value = true
}
// 编辑
function handleEdit(row: Student) {
currentStudent.value = { ...row }
dialogVisible.value = true
}
// 表单提交成功
function handleFormSuccess() {
run() // 刷新列表
}
</script>
<template>
<el-button type="primary" @click="handleAdd">新增学生</el-button>
<el-table :data="data?.list || []" border stripe>
<!-- ... -->
<el-table-column label="操作">
<template #default="{ row }">
<el-button type="primary" size="small" @click="handleEdit(row)">编辑</el-button>
</template>
</el-table-column>
</el-table>
<!-- 子组件 -->
<StudentForm
v-model="dialogVisible"
:student="currentStudent"
@success="handleFormSuccess"
/>
</template>
7.3 父子组件通信总结
| 方式 | 语法 | 说明 |
|---|---|---|
| 父传子 | defineProps |
父组件通过属性传递数据给子组件 |
| 子传父 | defineEmits |
子组件通过事件传递数据给父组件 |
| 双向绑定 | v-model |
父子组件同步数据(如对话框显示状态) |
类比 Java:类似于 Java 的接口定义,父组件定义"接口"(props + events),子组件"实现"接口。
八、完整案例:学生管理页面
将以上内容整合成一个完整的学生管理页面:
vue
<script setup lang="ts">
import { ref } from 'vue'
import { useRequest } from 'vue-request'
import { ElMessage, ElMessageBox } from 'element-plus'
import request from '@/api/request'
import StudentForm from '@/components/StudentForm.vue'
interface Student {
id: number
name: string
sex: string
age: number
}
// 查询参数
const queryParams = ref({
name: '',
sex: '',
page: 1,
size: 10
})
// 学生列表
const { data, total, loading, run } = useRequest(
() => request.get('/api/students/page', { params: queryParams.value }),
{
defaultParams: [queryParams.value],
pagination: {
currentKey: 'page',
pageSizeKey: 'size',
totalKey: 'data.total'
}
}
)
// 搜索
function handleSearch() {
queryParams.value.page = 1
run()
}
// 分页
function handlePageChange(page: number) {
queryParams.value.page = page
run()
}
// 删除
async function handleDelete(id: number) {
await ElMessageBox.confirm('确认删除?', '提示', { type: 'warning' })
await request.delete(`/api/students/${id}`)
ElMessage.success('删除成功')
run()
}
// 对话框
const dialogVisible = ref(false)
const currentStudent = ref<Student>()
function handleAdd() {
currentStudent.value = undefined
dialogVisible.value = true
}
function handleEdit(row: Student) {
currentStudent.value = { ...row }
dialogVisible.value = true
}
function handleFormSuccess() {
run()
}
</script>
<template>
<div class="student-manager">
<!-- 搜索栏 -->
<div class="search-bar">
<el-input v-model="queryParams.name" placeholder="姓名" clearable style="width: 150px" />
<el-select v-model="queryParams.sex" placeholder="性别" clearable style="width: 100px">
<el-option label="男" value="男" />
<el-option label="女" value="女" />
</el-select>
<el-button type="primary" @click="handleSearch">搜索</el-button>
<el-button type="primary" @click="handleAdd">新增</el-button>
</div>
<!-- 表格 -->
<el-table :data="data?.list || []" border stripe v-loading="loading">
<el-table-column prop="id" label="编号" width="100" />
<el-table-column prop="name" label="姓名" />
<el-table-column prop="sex" label="性别" />
<el-table-column prop="age" label="年龄" />
<el-table-column label="操作" width="150">
<template #default="{ row }">
<el-button type="primary" size="small" @click="handleEdit(row)">编辑</el-button>
<el-button type="danger" size="small" @click="handleDelete(row.id)">删除</el-button>
</template>
</el-table-column>
</el-table>
<!-- 分页 -->
<el-pagination
v-model:current-page="queryParams.page"
v-model:page-size="queryParams.size"
:total="total"
:page-sizes="[10, 20, 50]"
layout="total, sizes, prev, pager, next"
@current-change="handlePageChange"
/>
<!-- 新增/编辑对话框 -->
<StudentForm
v-model="dialogVisible"
:student="currentStudent"
@success="handleFormSuccess"
/>
</div>
</template>
<style scoped>
.student-manager {
padding: 20px;
}
.search-bar {
margin-bottom: 16px;
display: flex;
gap: 8px;
}
.el-pagination {
margin-top: 16px;
justify-content: flex-end;
}
</style>
总结
本文通过学生管理案例,系统讲解了 Element Plus 的核心组件:
| 组件 | 作用 | 关键点 |
|---|---|---|
el-table |
表格展示 | 自定义列用 #default="{ row }" 插槽 |
el-pagination |
分页导航 | 后端分页配合 :total 和 @current-change |
el-dialog |
对话框 | 双向绑定 v-model 控制显示 |
el-form |
表单 | 校验规则 :rules,手动校验 validate() |
ElMessage |
消息提示 | 成功/警告/错误提示 |
ElMessageBox |
确认框 | 删除等操作前确认 |
最佳实践:
- 复杂表单抽取为子组件,通过
defineProps/defineEmits通信 - 表单校验规则集中定义,类似 Java 的 validation 注解
- 分页由后端实现,前端只传递参数
下一步:掌握了单页面开发后,我们需要学习如何管理多个页面。下一篇文章将讲解 vue-router 路由管理。
作者:小张 | 转载请注明出处