Form表单与校验

第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
}

两个关键坑

  1. 先重置再赋值 :如果不先 resetFields(),上次编辑的数据会残留在新增弹窗中
  2. 逐字段赋值 :不能将表格行对象直接赋值给 formObject.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
某个字段永远不校验 proprules 键名、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
  • 新增/编辑复用:打开弹窗先重置,编辑时逐字段回填(避免引用污染)
  • 保存后刷新列表:调用接口成功后必须重新请求数据,保持界面与数据一致
相关推荐
我命由我123453 小时前
CesiumJS 笔记 - 获取容器中心点、Cartesian3 clone 方法、修改 Cartesian3 对象的高度
前端·javascript·css·前端框架·html·html5·js
抱抱宝4 小时前
Agent-study项目教程(03):手写 Mini-ReAct Agent(不依赖框架)
javascript·人工智能·gpt·react.js·prompt·agent
用户938515635075 小时前
Next.js 笔记系统(二):Redis 数据服务与侧边栏组件拆分实战
javascript·全栈
java1234_小锋6 小时前
Vue3专题 - 组件基础
vue.js·vite
Heo9 小时前
大厂前端调试不能只会debugger
前端·javascript·面试
windliang10 小时前
Claude Code 源码分析(十二):错误处理与自动恢复:让 Agent 稳定运行
前端·javascript·面试
默_笙10 小时前
🛬 前端路由的"高级玩法":懒加载、404、鉴权路由,一个都不能少(下篇)
前端·javascript
sunly_10 小时前
TypeScript:3、类型声明与类型推断
javascript·ubuntu·typescript
奥莱维11 小时前
【无标题】
java·前端·javascript
阿懂在掘金11 小时前
同一份弹窗我重构了三次:从 v-model 地狱到路由式调用,终于治好了模板臃肿
前端·vue.js·前端框架