Element Plus 和 Ant Design Vue 的表单组件都内置了基于 async-validator 的校验能力,实际使用体验非常接近。你不需要额外安装校验库,直接在表单组件上声明校验规则即可。
核心三要素
无论用哪个库,表单校验都离不开三个部分:
- 表单数据对象:一个响应式对象,存储所有表单项的值。
- 校验规则对象:一个对象,键名对应表单字段,值是校验规则数组或单个规则。
- 表单实例引用:用于手动触发全局校验或清除校验结果。
Element Plus 表单校验
基础结构
<template>
<el-form ref="formRef" :model="form" :rules="rules" label-width="80px">
<el-form-item label="用户名" prop="username">
<el-input v-model="form.username" />
</el-form-item>
<el-form-item label="邮箱" prop="email">
<el-input v-model="form.email" />
</el-form-item>
<el-form-item>
<el-button type="primary" @click="onSubmit">提交</el-button>
<el-button @click="onReset">重置</el-button>
</el-form-item>
</el-form>
</template>
<script setup>
import { ref, reactive } from 'vue'
const formRef = ref(null)
const form = reactive({
username: '',
email: ''
})
const rules = reactive({
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 onSubmit = async () => {
if (!formRef.value) return
try {
await formRef.value.validate()
// 校验通过,提交数据
console.log('提交:', form)
} catch (err) {
console.log('校验失败:', err)
}
}
const onReset = () => {
formRef.value?.resetFields()
}
</script>
关键点解析
el-form的model绑定数据对象,rules绑定校验规则。el-form-item的prop必须与model中的字段名一致,否则校验不会生效。- 校验规则中
trigger指定触发时机:'blur'失焦时、'change'值变化时,可以是数组。 formRef.value.validate()返回 Promise,校验通过 resolve,失败 reject。resetFields()会清空表单值和校验状态。
常用规则类型
| 规则 | 用途 | 示例 |
|------|------|------|
| required | 必填 | { required: true, message: '不能为空' } |
| type | 数据类型 | 'email'、'url'、'number'、'date' |
| min / max | 字符串长度或数字大小 | { min: 6, max: 20, message: '6-20位' } |
| pattern | 正则校验 | { pattern: /^1[3-9]\d{9}$/, message: '手机号格式错误' } |
| validator | 自定义校验函数 | 见下文 |
自定义校验函数
const validatePassword = (rule, value, callback) => {
if (value.length < 6) {
callback(new Error('密码长度不能少于6位'))
} else if (!/[A-Z]/.test(value)) {
callback(new Error('密码需包含大写字母'))
} else {
callback() // 通过校验
}
}
// 在 rules 中使用
password: [
{ required: true, message: '请输入密码', trigger: 'blur' },
{ validator: validatePassword, trigger: 'blur' }
]
注意:callback 必须调用,传入 Error 表示失败,不传或传空表示成功。
动态表单校验
当表单字段是动态循环生成的(如多个收货地址),prop 需要指向具体索引下的属性:
<el-form-item
v-for="(item, index) in form.addresses"
:key="index"
:label="'地址' + (index + 1)"
:prop="`addresses.${index}.street`"
:rules="[{ required: true, message: '请输入地址' }]"
>
<el-input v-model="item.street" />
</el-form-item>
手动触发单项校验
// 只校验邮箱字段
formRef.value.validateField('email', (valid) => {
if (!valid) {
console.log('邮箱不合法')
}
})
滚动到第一个错误
默认 Element Plus 不会自动滚动。可以这样做:
const onSubmit = async () => {
try {
await formRef.value.validate()
} catch {
// 找到第一个错误项并滚动到它
const firstError = document.querySelector('.is-error')
firstError?.scrollIntoView({ behavior: 'smooth', block: 'center' })
}
}
Ant Design Vue 表单校验
Ant Design Vue 3 的校验 API 几乎一致,只有组件名和少量细节差异。
基础结构
<template>
<a-form ref="formRef" :model="form" :rules="rules" layout="vertical">
<a-form-item label="用户名" name="username">
<a-input v-model:value="form.username" />
</a-form-item>
<a-form-item label="邮箱" name="email">
<a-input v-model:value="form.email" />
</a-form-item>
<a-form-item>
<a-button type="primary" @click="onSubmit">提交</a-button>
<a-button @click="onReset">重置</a-button>
</a-form-item>
</a-form>
</template>
<script setup>
import { ref, reactive } 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' }
]
}
const onSubmit = () => {
formRef.value.validate()
.then(() => console.log('提交:', form))
.catch(err => console.log('校验失败:', err))
}
const onReset = () => {
formRef.value.resetFields()
}
</script>
与 Element Plus 的差异
a-form-item使用name而非prop绑定字段。v-model双向绑定写法为v-model:value="form.xxx"(或简写v-model="form.xxx"在新版中已支持)。validate()同样返回 Promise,用法无异。- 自定义校验函数的参数略有不同:
(rule, value) => Promise,更推荐返回 Promise 而非使用 callback。
const validatePassword = (rule, value) => {
if (value.length < 6) {
return Promise.reject('密码长度不能少于6位')
} else if (!/[A-Z]/.test(value)) {
return Promise.reject('密码需包含大写字母')
} else {
return Promise.resolve()
}
}
实战经验与避坑
1. 校验时机
生产环境中往往希望“提交时才校验,输入过程中只做实时提示”。可以将规则的 trigger 设为 'change',但提交时强制全部校验;也可以设 trigger: 'blur',兼顾体验。
2. 避免重复提交
校验是异步的,在 validate 过程中记得禁用按钮,防止多次点击。
<a-button type="primary" :loading="submitting" @click="onSubmit">提交</a-button>
3. 表单清空resetFields() 会重置到初始值(即创建 form 时的默认值),而不是置空。如果你在数据加载后动态修改了 form 的值,再调用 resetFields() 会回退到最初状态,这可能导致预期不一致。建议在获取到数据后,重新赋值整个 form 对象,或手动逐个字段清空。
4. 嵌套对象校验
如果 model 是嵌套对象,如 { user: { name: '' } },则 prop 需写成 'user.name',且在 rules 中需要用 'user.name' 作为键名。Ant Design Vue 的 name 同样支持路径写法。
5. 动态规则
根据业务需要动态切换校验规则,可以将 rules 定义为计算属性:
const rules = computed(() => {
const baseRules = { /* 基础规则 */ }
if (isStrict.value) {
baseRules.password.push({ pattern: /[!@#$%]/... })
}
return baseRules
})
6. 只校验部分字段
调用 validateField('email') 或 validateFields(['email']),避免全量校验。
总结
Element Plus 和 Ant Design Vue 的表单校验都是配置式的,你只需定义好规则,调用 validate() 就能完成数据合法性检查。实际工作中绝大多数校验需求都能通过 required、type、pattern 和简单的自定义函数解决。当遇到特别复杂的多字段联动校验(如“结束时间必须晚于开始时间”),可以在自定义 validator 中访问整个 model 对象来实现。