人人都会AI编程

16.2 VeeValidate:声明式表单校验方案

更新时间:2026-07-09

原生的 v-model 结合 computedwatch 可以做简单校验,但当表单字段变多、校验规则变复杂(如联动校验、异步校验)时,手写校验逻辑很快就会让组件变得臃肿难读。这时就需要一个专项表单校验库来把规则声明化,让模板和逻辑都保持干净。

VeeValidate 是 Vue 生态中最成熟的表单校验方案之一。它的核心思路是:在模板上用组件和指令声明校验规则,由 VeeValidate 自动追踪值变化、执行校验、收集错误信息,开发者只用关注业务逻辑,不用再手写一堆 if/elseref 来维护错误状态。

安装与快速上手

npm install vee-validate

VeeValidate 暴露了一套组合式函数和组件,最常用的入口是在 main.js 中进行全局注册:

import { createApp } from 'vue'
import { Field, Form, ErrorMessage, defineRule, configure } from 'vee-validate'
import { required, email } from '@vee-validate/rules'   // 按需导入规则
import { localize } from '@vee-validate/i18n'
import zhTW from '@vee-validate/i18n/dist/locale/zh_TW.json'

// 定义全局规则
defineRule('required', required)
defineRule('email', email)

// 配置全局行为
configure({
  generateMessage: localize('zh_TW')  // 错误信息中文化
})

const app = createApp(App)
app.component('Field', Field)
app.component('Form', Form)
app.component('ErrorMessage', ErrorMessage)
app.mount('#app')

如果不想全局注册,也可以在单个组件里按需引入。

核心用法:用组件替代原生标签

原本你可能会这样写校验:

<input v-model="email" @blur="validateEmail" />
<span v-if="emailError">{{ emailError }}</span>

VeeValidate 则让你用 <Field> 组件替换原生输入框,并把校验规则写在 rules 属性上:

<Form @submit="handleSubmit">
  <label>邮箱</label>
  <Field name="email" type="email" rules="required|email" />
  <ErrorMessage name="email" />

  <button type="submit">提交</button>
</Form>

发生了什么:

  • <Field> 内部渲染一个 <input>,并自动处理 v-model 和校验触发(默认为 blurchange)。
  • rules="required|email" 声明了两个校验规则,用管道符 | 分隔,依次执行。
  • <ErrorMessage name="email"> 会自动显示当前字段对应的第一项错误信息,无需手动控制显隐。
  • <Form> 包裹整个表单,提供 @submit 事件,该事件只在所有字段校验通过后才触发。

规则怎么写:内置规则与链式组合

VeeValidate 提供大量开箱即用的规则:

| 规则 | 说明 | 示例 |
|------|------|------|
| required | 必填 | rules="required" |
| email | 邮箱格式 | rules="email" |
| min:6 | 最小长度/数值 | rules="min:6" |
| max | 最大长度/数值 | rules="max:20" |
| confirmed | 确认字段(如密码确认) | rules="confirmed:@password" |
| regex | 正则匹配 | rules="regex:^[a-zA-Z]+$" |

也可以给一个字段同时指定多条规则:

<Field name="password" rules="required|min:8|max:20" />

自定义规则与异步校验

业务里难免有特殊逻辑,比如“用户名不能已存在”。VeeValidate 的自定义规则很简单——一个返回布尔或错误信息的函数:

import { defineRule } from 'vee-validate'

defineRule('uniqueUsername', async (value) => {
  if (!value) return true
  const exists = await api.checkUsername(value)      // 模拟异步接口
  if (exists) {
    return '该用户名已被注册'
  }
  return true
})

然后在 rules 中使用 uniqueUsername 即可。异步校验会自动等待 Promise resolve,校验期间字段会进入 pending 状态,UI 上可以展示加载态。

错误信息与本地化

@vee-validate/i18n 提供了 40+ 语言包,简单引入就能把 required 的英文提示“The XX field is required”换成中文“XX 字段是必填的”。如果某个字段需要个性化文案,可以直接在规则中传参:

<Field name="title" :rules="{ required: true, max: { length: 10, message: '标题最多10个字' } }" />

或者用 ErrorMessage 的作用域插槽做自定义渲染:

<ErrorMessage name="email" v-slot="{ errors }">
  <div v-for="error in errors" :key="error" class="error-tip">{{ error }}</div>
</ErrorMessage>

手动校验与表单重置

有些场景需要显式触发表单校验,比如点击“保存草稿”时不校验,点击“提交”时完整校验。你可以通过 useForm 组合式函数拿到校验方法:

<script setup>
import { useForm } from 'vee-validate'

const { handleSubmit, resetForm, errors, values } = useForm()

const submit = handleSubmit((formValues) => {
  console.log('校验通过,表单数据:', formValues)
  api.save(formValues)
})
</script>

resetForm() 可以清空所有字段的输入值和错误状态,非常适合关闭弹窗时调用。errors 对象让你可以自由判断哪个字段有错误,比如通过 errors.email 获取邮箱的详细错误。

什么时候用 VeeValidate

  • 你的表单比较复杂,包含动态添加字段、嵌套对象数组、字段联动禁用等逻辑。
  • 你需要统一且可维护的校验规则管理,而不是把规则散落在一堆内联函数中。
  • 团队希望减少模板中关于校验状态的重复代码,把 v-if=“emailError” 这类逻辑交给库处理。
  • 项目不要求必须强绑定某一套 UI 组件库的校验风格,或者你用的是非 Element/Ant Design 体系的 UI 框架(如 Tailwind、Naive UI 的 core 包)。

如果你的项目已经深度使用 Element Plus 或 Ant Design Vue,并且所有表单都直接套用它们的 <el-form> 组件和内置校验规则,那 VeeValidate 可能不是必需品(16.3 节会讲)。但若你需要一份跨组件库统一、更灵活的方案,或者你在开发一个需要完全自定义 UI 的项目,VeeValidate 就是那个“让表单校验回归声明式”的好帮手。