Skip to content
第 24 章 前端 ⏱ 13 分钟阅读

第 24 章:表单与校验 ​

学习目标 ​

  • 写 async-validator 规则
  • 嵌套 / 数组 / 异步校验
  • 自己写校验规则
  • 避坑:trigger 时机

一、最简表单 ​

vue
<template>
  <el-form :model="form" :rules="rules" ref="formRef" label-width="80px">
    <el-form-item label="用户名" prop="username">
      <el-input v-model="form.username" />
    </el-form-item>
    <el-form-item label="密码" prop="password">
      <el-input v-model="form.password" type="password" />
    </el-form-item>
    <el-button @click="submit">提交</el-button>
  </el-form>
</template>

<script setup lang="ts">
import type { FormInstance, FormRules } from 'element-plus'

const formRef = ref<FormInstance>()
const form = reactive({ username: '', password: '' })

const rules: FormRules = {
  username: [{ required: true, message: '必填', trigger: 'blur' }],
  password: [
    { required: true, message: '必填', trigger: 'blur' },
    { min: 6, message: '至少 6 位', trigger: 'blur' },
  ],
}

const submit = async () => {
  await formRef.value?.validate()
  await api.save(form)
}
</script>

⚠️ 坑 1:rules 必须用 FormRules 类型,否则 TS 推断为 any。

二、内置校验规则 ​

规则说明
required必填
min / max长度 / 数值
pattern正则
type: 'email'邮箱
type: 'url'URL
validator自定义函数

三、自定义校验 ​

ts
const validatePass2 = (_: any, value: string, cb: (err?: Error) => void) => {
  if (value !== form.password) cb(new Error('两次密码不一致'))
  else cb()
}

const rules: FormRules = {
  password2: [{ validator: validatePass2, trigger: 'blur' }],
}

四、异步校验 ​

ts
const validateUsername = async (_: any, value: string, cb: (err?: Error) => void) => {
  try {
    const res = await api.checkUsername(value)
    if (res.exists) cb(new Error('用户名已被占用'))
    else cb()
  } catch (e) {
    cb()
  }
}

五、嵌套字段 ​

ts
const form = reactive({
  user: { name: '', email: '' },
})

const rules: FormRules = {
  'user.name': [{ required: true }],
  'user.email': [{ type: 'email' }],
}

⚠️ 坑 2:嵌套字段必须用字符串路径,不能传 user.name 字段路径对象。

六、数组字段 ​

vue
<el-form-item
  v-for="(item, i) in form.items"
  :key="i"
  :prop="`items.${i}.name`"
  :rules="{ required: true, message: '必填' }"
>
  <el-input v-model="item.name" />
</el-form-item>

七、整体重置 ​

ts
formRef.value?.resetFields()    // 还原到初始值
formRef.value?.clearValidate()  // 只清除校验

⚠️ 坑 3:resetFields 只能重置到 form 初始值,如果 form 是 reactive 后续被改,reset 会回到那个被改的"初始"。

八、控台校验 ​

ts
const submit = async () => {
  try {
    await formRef.value?.validate()
    // 校验通过
  } catch {
    ElMessage.error('请检查表单')
  }
}

九、实战:注册表单 ​

ts
const rules: FormRules = {
  username: [
    { required: true, message: '必填' },
    { pattern: /^[a-z][a-z0-9_]{2,15}$/, message: '字母数字下划线,3-16 位' },
  ],
  email: [
    { required: true, message: '必填' },
    { type: 'email', message: '格式错误' },
  ],
  password: [
    { required: true },
    { validator: (rule, value, cb) => {
      if (!/[A-Z]/.test(value)) cb(new Error('需含大写'))
      else cb()
    } },
  ],
}

十、本章小结 ​

能力关键
rules:rules + prop 对应
validator(rule, value, cb)
嵌套'a.b.c' 字符串路径
数组items.${i}.name
重置resetFields / clearValidate

动手练习 ​

  1. 注册表单:用户名 / 邮箱 / 密码,带正则
  2. 密码确认:两次密码一致性校验
  3. 异步校验:用户名查重

下一章:第 25 章:权限控制 →

本站基于 VitePress 构建 · 由 StackHub 团队维护