第13课 Form表单与校验
- 使用
el-form搭建规范的表单,掌握数据绑定与控件用法 - 配置表单校验规则(必填、格式、长度),理解
prop/rules/model三者的绑定关系 - 实现校验通过才提交的完整流程,包含新增与编辑回填场景
1. el-form 表单基础
1.1 核心组成
| 标签/属性 | 作用 | 类比 |
|---|---|---|
el-form |
表单容器(整张登记表) | 表格纸 |
el-form-item |
表单的一行,label 为该行标题 |
"姓名:____"这一行 |
:model="form" |
将表单组件与数据对象绑定(答题卡底稿) | 背后的电子记录 |
v-model="form.xxx" |
控件双向绑定到底稿的字段 | 笔尖落进格子 |
1.2 基本模板骨架
html
<el-form :model="form" label-width="90px">
<el-form-item label="用户名">
<el-input v-model="form.name" placeholder="请输入" />
</el-form-item>
<el-form-item label="角色">
<el-select v-model="form.role" placeholder="请选择">
<el-option label="管理员" value="管理员" />
<el-option label="编辑" value="编辑" />
</el-select>
</el-form-item>
<el-form-item label="状态">
<el-radio-group v-model="form.status">
<el-radio value="启用">启用</el-radio>
<el-radio value="停用">停用</el-radio>
</el-radio-group>
</el-form-item>
</el-form>
label-width统一行标题宽度(防止表格歪扭)form对象中的每个字段必须设置初始值(空字符串),否则后续重置时该字段无法被重置
2. 校验规则 (rules)
2.1 规则配置结构
js
const rules = {
name: [
{ required: true, message: '请输入用户名', trigger: 'blur' },
{ min: 2, max: 10, message: '长度在 2 到 10 个字符', trigger: 'blur' }
],
phone: [
{ required: true, message: '请输入手机号', trigger: 'blur' },
{ validator: checkPhone, trigger: 'blur' }
],
email: [
{ required: true, message: '请输入邮箱', trigger: 'blur' },
{ type: 'email', message: '邮箱格式不正确', trigger: 'blur' }
],
role: [
{ required: true, message: '请选择角色', trigger: 'change' }
]
}
每条规则包含三个要素:查什么 (required/min/type/validator)、不通过时说什么 (message)、什么时候查 (trigger)。
2.2 常见校验类型
| 类型 | 写法示例 | 适用字段 |
|---|---|---|
| 必填 | { required: true, message: '...', trigger: 'blur' } |
所有必填项 |
| 长度 | { min: 2, max: 10, message: '...', trigger: 'blur' } |
用户名、密码 |
| 内置格式 | { type: 'email', message: '...', trigger: 'blur' } |
邮箱、网址 |
| 自定义格式 | { validator: checkFn, trigger: 'blur' } |
手机号、身份证等 |
trigger 选择规则 :输入框使用 blur(失焦时校验,避免一边输入一边报错),下拉框/单选框使用 change(值变化立刻校验)。
2.3 自定义校验函数
js
function checkPhone(rule, value, callback) {
if (!value) return callback() // 空值交给 required 处理
const reg = /^1[3-9]\d{9}$/
if (reg.test(value)) {
callback() // 通过:不传任何参数
} else {
callback(new Error('手机号格式不正确(11位数字)'))
}
}
validator 函数接收三个参数:rule(规则本身)、value(当前值)、callback(结果回调)。
2.4 让规则生效:prop 绑定
html
<el-form ref="formRef" :model="form" :rules="rules">
<el-form-item label="用户名" prop="name">
<el-input v-model="form.name" />
</el-form-item>
</el-form>
核心规则 :prop 的值、rules 对象的键名、model 对象里的字段名,三者必须完全一致。写错任何一个,该字段将永不校验。
3. 提交、校验与重置
3.1 校验与提交(Promise 写法)
js
const formRef = ref(null)
async function handleSubmit() {
try {
await formRef.value.validate() // 异步校验,通过才继续
// 能走到这里说明全部校验通过
ElMessage.success('提交成功')
} catch {
ElMessage.error('还有没填对的地方,请看红字提示')
}
}
validate()是异步方法,必须await等待结果- 校验通过 → 继续执行 try 内后续代码
- 校验失败 → 直接跳入 catch,已在表单项下方显示红字
3.2 重置表单
js
function handleReset() {
formRef.value.resetFields() // 将所有字段恢复到初始值并清除红字
}
注意 :resetFields() 重置到的是表单对象最初定义时的值 (如空字符串),而非单纯"清空"。因此 form 中每个字段必须显式定义初始值,否则不会被重置。
3.3 提交时按钮防连点
html
<el-button type="primary" :loading="saving" @click="handleSave">保存</el-button>
:loading="saving"保存中按钮显示转圈并禁用saving.value = true在请求前设置,finally中置回false
4. 实战:新增/编辑用户弹窗表单
4.1 数据层(api/user.js)
js
// 新增用户(模拟后端接口,真实项目替换为 axios 请求)
export function createUser(userData) {
return new Promise((resolve) => {
setTimeout(() => {
const newUser = { id: mockUsers.length + 1, ...userData, createdAt: '...' }
mockUsers.unshift(newUser) // 插入到数组头部,列表第一页可见
resolve(newUser)
}, 600)
})
}
// 更新用户
export function updateUser(id, userData) {
return new Promise((resolve) => {
setTimeout(() => {
const target = mockUsers.find(u => u.id === id)
if (target) Object.assign(target, userData) // 覆盖业务字段
resolve(target)
}, 600)
})
}
4.2 弹窗与表单结构(UserListView.vue)
html
<el-dialog v-model="dialogVisible" :title="editingId ? '编辑用户' : '新增用户'" width="480px">
<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 v-if="!editingId" label="密码" prop="password">
<el-input v-model="form.password" type="password" show-password />
</el-form-item>
</el-form>
<template #footer>
<el-button @click="dialogVisible = false">取消</el-button>
<el-button type="primary" :loading="saving" @click="handleSave">保存</el-button>
</template>
</el-dialog>
- 密码字段仅在新增时显示(
v-if="!editingId"),编辑时不显示、不校验 - 弹窗标题根据
editingId动态切换
4.3 打开弹窗逻辑(防止数据残留)
js
function openDialog(user) {
formRef.value?.resetFields() // ★ 先重置表单(清空输入和红字)
if (user) {
// 编辑模式:逐字段赋值回填(不可直接引用表格行对象)
editingId.value = user.id
form.name = user.name
form.phone = user.phone
form.email = user.email
form.role = user.role
form.status = user.status
form.password = ''
} else {
editingId.value = null // 新增模式
}
dialogVisible.value = true
}
两个关键坑:
- 先重置再赋值 :如果不先
resetFields(),上次编辑的数据会残留在新增弹窗中 - 逐字段赋值 :不能将表格行对象直接赋值给
form(Object.assign(form, user)),否则修改表单会污染表格数据(同一个引用)
4.4 保存逻辑
js
async function handleSave() {
try {
await formRef.value.validate() // 校验
const payload = {
name: form.name,
phone: form.phone,
email: form.email,
role: form.role,
status: form.status
}
saving.value = true
if (editingId.value) {
await updateUser(editingId.value, payload)
ElMessage.success('修改成功')
} else {
await createUser(payload)
ElMessage.success('新增成功')
}
dialogVisible.value = false
loadUserList() // ★ 重新拉取列表,展示最新数据
} catch {
ElMessage.error('还有没填对的地方,请看红字提示')
} finally {
saving.value = false
}
}
5. 常见错误排查
| 现象 | 原因 | 解决 |
|---|---|---|
| 所有字段都不校验 | el-form 没挂 :rules 或所有项缺少 prop |
确保 :rules="rules" 且每个 el-form-item 写了 prop |
| 某个字段永远不校验 | prop 与 rules 键名、model 字段名不一致 |
确保三个名称完全一致 |
| 输入时每敲一个字符就报错 | 输入框的 trigger 写成了 change |
输入框改用 blur,下拉/单选用 change |
| 下拉框选择后无反应 | 下拉框的 trigger 写成了 blur |
下拉框改为 trigger: 'change' |
| 点提交不校验也不提示 | 未调用 validate() 或 formRef 名称不一致 |
确认 formRef.value.validate() 已被调用 |
| 校验失败但代码仍然往下执行 | validate() 未使用 await |
使用 try { await validate() } catch { } 包裹 |
| 重置后表单未清空 | form 对象中缺少某些字段的初始值 |
确保所有字段在 form 中都定义了初始值 |
| 编辑后再次新增仍显示旧数据 | 打开弹窗前未调用 resetFields() |
在 openDialog 函数第一行重置表单 |
| 编辑保存后表格数据未更新 | 保存成功后未刷新列表 | 在 handleSave 成功回调中调用 loadUserList() |
| 组件样式丢失(裸奔) | 未引入 Element Plus 样式文件 | 在 main.js 中引入 import 'element-plus/dist/index.css' |
总结
- 表单搭建 :
el-form(整张表)→el-form-item(一行)→ 控件 +v-model(填格子) - 校验规则 :
rules对象为每个字段配置规则,prop将规则与表单项绑定(三名一致) - 提交流程 :
await validate()→ 通过后执行业务 →finally关闭 loading - 新增/编辑复用:打开弹窗先重置,编辑时逐字段回填(避免引用污染)
- 保存后刷新列表:调用接口成功后必须重新请求数据,保持界面与数据一致