Skip to content

参考 ​

基于 vee-validate v4 编写。完整 API 见 官方文档。

核心 API ​

useForm(options) ​

ts
import { useForm } from "vee-validate";

const form = useForm({
  // schema 或字段规则二选一
  validationSchema?: GenericValidateFunction | Schema,
  initialValues?: Partial<TValues>,
  initialErrors?: Partial<Record<string, string>>,
  initialTouched?: Partial<Record<string, boolean>>,
  validateOnMount?: boolean,        // mount 时立即校验
  keepValuesOnUnmount?: boolean,    // 字段 unmount 后保留值
  controlled?: boolean,             // 是否对接 v-model
});

返回值见 指南:表单级方法。

defineField(name, configOrFn?) ​

ts
const [model, attrs] = defineField("email", {
  validateOnInput?: boolean,
  validateOnBlur?: boolean,
  validateOnChange?: boolean,
  validateOnModelUpdate?: boolean,
  props?: (state: FieldState) => Record<string, unknown>,
  label?: string,
  syncVModel?: boolean | string,
});

返回 [Ref<TValue>, Ref<{ onChange, onBlur, onInput, ... }>]。

useField(name, rules?, opts?) ​

底层 API,defineField 内部用它。手动绑定时:

ts
const { value, errors, errorMessage, meta, handleChange, handleBlur, validate } = useField(
  "email",
  "required|email",
);
字段类型说明
valueRef<TValue>字段值
errorsRef<string[]>当前所有错误
errorMessageRef<string>第一条错误
metaFieldMeta字段元数据
handleChangeFunction触发 change
handleBlurFunction触发 blur
validate() => Promise手动校验
resetFieldFunction重置该字段
setValueFunction设置值并校验
setErrorsFunction设置错误(不触发校验)
setTouchedFunction设置 touched 状态

useFieldArray(name) ​

ts
const {
  fields, push, prepend, insert, remove, swap, move, replace, update,
} = useFieldArray<TItem>("links");

详见 指南:FieldArray 进阶。

defineRule(name, fn) ​

ts
import { defineRule } from "vee-validate";

defineRule("ruleName", (
  value: unknown,
  params: unknown[],
  ctx: { form: FormValues, field: string, name: string, label?: string },
) => true | string | Promise<true | string>);

返回 true 通过,返回字符串作错误消息。

configure(opts) ​

全局配置:

ts
import { configure } from "vee-validate";

configure({
  // 触发行为默认
  validateOnInput: false,
  validateOnBlur: true,
  validateOnChange: false,
  validateOnModelUpdate: true,

  // 错误消息生成器
  generateMessage: (ctx) => `${ctx.field} is invalid`,

  // 字段命名风格
  bails: true, // true: 第一条规则失败即停(默认)
});

声明式组件 ​

<Form> ​

Prop类型说明
validation-schemaSchema / Function校验 schema
initial-valuesobject初始值
initial-errorsobject初始错误
validate-on-mountbooleanmount 即校验
keep-valuesboolean卸载字段保留值
asstring渲染为指定 tag(默认 form)
Slot prop类型
valuesFormValues
errorsRecord<string, string>
errorBagRecord<string, string[]>
metaFormMeta
isSubmittingboolean
isValidatingboolean
submitCountnumber
handleSubmitFunction
resetFormFunction
setFieldValueFunction
setErrorsFunction
validateFunction

<Field> ​

Prop类型说明
namestring必填,字段名
rulesstring / object / Function字段级规则(模板字符串或函数)
asstring渲染为指定 tag,默认 input
typestringinput type
value-复选框/单选时设值
unchecked-value-复选框未选时的值
standaloneboolean脱离 <Form> 校验上下文
keep-valueboolean卸载保留值
validate-on-mountbooleanmount 即校验该字段
validate-on-blurboolean-
validate-on-inputboolean-
validate-on-changeboolean-
Slot prop类型
field{ value, onInput, onBlur, onChange, ... }
errorsstring[]
errorMessagestring
metaFieldMeta
handleChangeFunction
handleBlurFunction
resetFieldFunction
setValueFunction
validateFunction

<ErrorMessage> ​

vue
<ErrorMessage name="email" class="text-red-500" as="p" />
Prop类型说明
namestring必填
asstring渲染 tag,默认 <span>

无 slot props 时默认渲染错误文本;有 slot 时:

vue
<ErrorMessage name="email" v-slot="{ message }">
  <p v-if="message" class="err">⚠️ {{ message }}</p>
</ErrorMessage>

<FieldArrayItems> ​

v4.13+ 提供的声明式 FieldArray:

vue
<FieldArrayItems name="links" v-slot="{ fields, push, remove, swap }">
  <div v-for="(item, idx) in fields" :key="item.key">
    <Field :name="`links[${idx}].url`" />
    <button @click="remove(idx)">×</button>
  </div>
  <button @click="push({ url: '' })">+</button>
</FieldArrayItems>

内置规则 (@vee-validate/rules) ​

bash
pnpm add @vee-validate/rules
规则参数作用
required-必填(空字符串 / null / undefined 失败)
email-邮箱格式
minnumber字符串最小长度 / 数字最小值
maxnumber字符串最大长度 / 数字最大值
min_valuenumber仅数字最小值
max_valuenumber仅数字最大值
betweenmin, max数字在区间内
lengthnumber字符串精确长度
numeric-仅数字
integer-仅整数
decimaldigits小数位
alpha-仅字母
alpha_num-字母 + 数字
alpha_dash-字母 + 数字 + - + _
alpha_spaces-字母 + 空格
url-URL 格式
regexpattern正则匹配
confirmedtarget与另一字段相等
not_one_ofvalues...不能是某些值
one_ofvalues...必须是某些值之一
image-File 是图片
mimesmime1, mime2File MIME 校验
sizekbFile 大小 ≤ kb
dimensionswidth, height图片尺寸
extext1, ext2文件扩展名
isvalue严格相等
is_notvalue严格不等

注册全部:

ts
import { defineRule } from "vee-validate";
import { all } from "@vee-validate/rules";

Object.entries(all).forEach(([k, r]) => defineRule(k, r));

按需注册:

ts
import { required, email, min } from "@vee-validate/rules";

defineRule("required", required);
defineRule("email", email);
defineRule("min", min);

Schema 适配器 API ​

@vee-validate/zod ​

ts
import { toTypedSchema } from "@vee-validate/zod";

toTypedSchema(zodSchema): TypedSchema

@vee-validate/yup ​

ts
import { toTypedSchema } from "@vee-validate/yup";

toTypedSchema(yupSchema): TypedSchema

@vee-validate/valibot ​

ts
import { toTypedSchema } from "@vee-validate/valibot";

toTypedSchema(valibotSchema): TypedSchema

@vee-validate/joi ​

ts
import { toTypedSchema } from "@vee-validate/joi";

toTypedSchema(joiSchema): TypedSchema

i18n API ​

localize(messagesMap) ​

ts
import { localize } from "@vee-validate/i18n";
import zhCN from "@vee-validate/i18n/dist/locale/zh_CN.json";

const generateMessage = localize({
  "zh-CN": {
    ...zhCN,
    names: { email: "邮箱" },        // 字段显示名
    fields: {                         // 字段级覆盖
      email: { required: "邮箱不能为空" },
    },
  },
});

configure({ generateMessage });

setLocale(locale) ​

ts
import { setLocale } from "@vee-validate/i18n";

setLocale("en"); // 切语言

内置 locale 列表(部分) ​

ar, az, be, bg, bn, ca, cs, da, de, dv, el, en, eo, es, et, eu, fa, fi, fr, gl,
he, hi, hr, hu, hy, id, it, ja, ka, kk, km, ko, ku, lt, lv, mk, mn, ms, my, nb,
ne, nl, no, pa, pl, pt_BR, pt_PT, ro, ru, sk, sl, sq, sr, sr_Cyrl, sv, ta, th,
tr, uk, uz, vi, zh_CN, zh_TW

按需 import:

ts
import zhCN from "@vee-validate/i18n/dist/locale/zh_CN.json";
import en from "@vee-validate/i18n/dist/locale/en.json";

Nuxt 模块 (@vee-validate/nuxt) ​

ts
// nuxt.config.ts
export default defineNuxtConfig({
  modules: ["@vee-validate/nuxt"],
  veeValidate: {
    autoImports?: boolean,           // 自动 import useForm / useField 等
    componentNames?: {               // 重命名内置组件(避免冲突)
      Form?: string,
      Field?: string,
      FieldArray?: string,
      ErrorMessage?: string,
    },
  },
});

TypeScript 工具类型 ​

ts
import type {
  FieldMeta,
  FormMeta,
  ValidationResult,
  FormValidationResult,
  GenericValidateFunction,
  TypedSchema,
  PathValue,
  Path,
} from "vee-validate";

// 取 schema 推导出的 form values 类型
type Values = z.infer<typeof zodSchema>;

触发时机决策表 ​

用户场景推荐触发
邮箱、用户名等格式校验validateOnBlur: true(输入完才校验)
密码强度提示validateOnInput: true(实时反馈)
数字范围validateOnChange: true
异步唯一性(如邮箱已注册)validateOnBlur + debounce
跨字段依赖(如二次密码)任一字段改变都校验,validateOnInput
整表 / 大型校验validateOnInput: false,仅 submit 校验

与其它表单库对比 ​

库风格TS 支持适配器包体推荐场景
vee-validate声明 + Composition★★★Zod/Yup/Valibot/Joi~20KBVue 项目复杂表单首选
FormKit全配置驱动★★自家 schema~70KB大量重复表单(CMS / 后台)
Naive UI Form内置★★Yup 风格-用 Naive UI 时直接用
Element Form内置★async-validator-用 Element Plus 时直接用
Custom(ref)手写-任意<1KB1-3 字段的简单表单

性能基线 ​

参考数字(M1 MacBook,Chrome 122):

操作耗时
useForm 创建< 1ms
单字段校验(同步规则)< 0.5ms
单字段校验(Zod schema 命中)1-3ms
FieldArray push 100 项~50ms
FieldArray push 1000 项500ms+(建议虚拟滚动)
整表 validate(50 字段)10-30ms
异步规则(含 fetch)网络 RTT

版本里程碑 ​

版本时间主要变化
v32020Vue 2 时代,Provider / ValidationObserver 组件式
v4.02021重写为 Vue 3 原生,提供 useForm / useField
v4.102023defineField 替代 useFieldModel
v4.112023标准化 Composition API 触发选项
v4.132024<FieldArrayItems> 声明式 FieldArray
v4.142024TypedSchema 推导改进
v4.152025keepValuesOnUnmount 表单级配置

参考链接 ​