airi 中的 Vue 响应式表单校验:useAsyncValidator 声明式校验实战指南
airi 中的 Vue 响应式表单校验:useAsyncValidator 声明式校验实战指南
useAsyncValidator 是 VueUse @Integrations 系列中封装 async-validator(Ant Design Vue / Element Plus 表单校验同款引擎)的响应式组合式函数,它把「校验数据 + 校验规则」直接绑定进 Vue 的响应式系统,让表单校验状态(是否通过、错误信息、错误字段)无需手写订阅即可自动更新。在 airi 仓库中,它被收录于 .agents/skills/vueuse-functions 技能库(对应官方 VueUse v14.4.0),供 Vue 3 / Nuxt 3 项目按需接入。读完本文,你将掌握 useAsyncValidator 的安装方式、选项与返回值语义、声明式规则写法,以及如何用它替代手写校验逻辑。
useAsyncValidator 是什么
useAsyncValidator 是 async-validator 的响应式包装器(Wrapper)。async-validator 本身是一个纯函数式、面向 descriptor(描述符)的异步校验库:你定义一组规则(Rules),它针对某个数据对象执行校验,返回错误列表。VueUse 将其包装后,实现了两点关键增强:
- 响应式联动:校验对象
value与校验规则rules都可以是ref/getter/ 普通对象,任一变化都会触发重新校验; - 结果状态化:校验结果(
pass、errors、errorFields等)以ShallowRef/ComputedRef暴露,可直接用于模板渲染与逻辑判断。
在 airi 的 vueuse-functions 技能体系中,该函数被归类为 @Integrations(第三方库集成)类别,调用规则为 EXTERNAL:只有项目已安装 async-validator 时才使用,不应作为默认依赖自动引入(见 SKILL.md)。
安装 async-validator
由于 useAsyncValidator 属于 @vueuse/integrations 包,而 async-validator 是它的可选 peer 依赖,使用时需要显式安装:
npm i async-validator@^4
在 pnpm workspace 的 airi 仓库中,这一依赖关系同样有据可查:pnpm-lock.yaml 显示 @vueuse/integrations@14.4.0 的 peerDependencies 声明了 async-validator: ^4,且标记为 optional(peerDependenciesMeta.async-validator.optional: true),意味着 @vueuse/integrations 本身可选装,只有实际使用 useAsyncValidator 时才需要补装 async-validator@^4(pnpm-lock.yaml)。若使用 pnpm,可直接:
pnpm add @vueuse/integrations async-validator@^4
基本用法与导入
在 Vue 3 组件(或 Nuxt 3)中导入:
import { useAsyncValidator } from '@vueuse/integrations/useAsyncValidator'
注意导入路径来自 @vueuse/integrations 子路径,而非 @vueuse/core。函数签名如下:
export declare function useAsyncValidator(
value: MaybeRefOrGetter<Record<string, any>>, // 待校验数据
rules: MaybeRefOrGetter<Rules>, // async-validator 规则描述符
options?: UseAsyncValidatorOptions, // 可选配置
): UseAsyncValidatorReturn & PromiseLike<UseAsyncValidatorReturn>
value:校验目标,类型为Record<string, any>,支持传入普通对象、ref或 getter(MaybeRefOrGetter);rules:async-validator的规则对象,同样支持响应式传入;- 返回值同时实现了
PromiseLike,因此可以await useAsyncValidator(...)直接获取结果。
最小可用示例
import { reactive } from 'vue'
import { useAsyncValidator } from '@vueuse/integrations/useAsyncValidator'
const form = reactive({ username: '', email: '' })
const { pass, errors, errorFields } = useAsyncValidator(form, {
username: { required: true, message: '用户名不能为空' },
email: { type: 'email', message: '邮箱格式不正确' },
})
默认情况下(immediate: true、manual: false),首次调用即触发校验,此后 form.username / form.email 一旦变化,校验会自动重新执行,pass、errors 等状态同步更新——无需手动监听数据。
选项配置详解
UseAsyncValidatorOptions 共三个字段,控制校验的触发时机:
| 选项 | 类型 | 默认值 | 说明 |
|---|---|---|---|
validateOption |
ValidateOption |
无 | 透传给 async-validator 的底层校验选项 |
immediate |
boolean |
true |
是否立即触发首次校验;仅在 manual 未开启时生效 |
manual |
boolean |
false |
设为 true 后,关闭自动校验,只能手动调用 execute() |
manual + execute 手动触发模式
当需要「提交时才校验」(典型如登录表单、保存按钮)时:
const { execute, pass, errorInfo } = useAsyncValidator(
form,
rules,
{ immediate: false, manual: true },
)
// 提交按钮
async function onSubmit() {
const result = await execute()
if (!result.pass) {
console.log(result.errorInfo)
return
}
// 校验通过,继续提交
}
manual: true 与 immediate 的组合需要留意:immediate 只在 manual 未开启时生效,因此手动模式下 immediate 的设置会被忽略。
validateOption 透传
validateOption 会原样转发给 async-validator 的 validate() 方法(官方称为 ValidateOption),典型用途包括 first(遇首个错误即停止)与 firstFields(按字段遇错即停),用于控制错误上报粒度。文档源码中以 @see 形式指向 async-validator 官方 options 说明(见 useAsyncValidator.md),实际可用的字段以所安装的 async-validator@^4 版本为准。
返回值语义与类型声明
useAsyncValidator 返回 UseAsyncValidatorReturn & PromiseLike<UseAsyncValidatorReturn>,其中 UseAsyncValidatorReturn 与单次执行的 UseAsyncValidatorExecuteReturn 结构如下(完整类型见 useAsyncValidator.md):
export type AsyncValidatorError = Error & {
errors: ValidateError[] // 全部错误数组
fields: Record<string, ValidateError[]> // 按字段分组
}
export interface UseAsyncValidatorExecuteReturn {
pass: boolean
errors: AsyncValidatorError['errors'] | undefined
errorInfo: AsyncValidatorError | null
errorFields: AsyncValidatorError['fields'] | undefined
}
export interface UseAsyncValidatorReturn {
pass: ShallowRef<boolean>
isFinished: ShallowRef<boolean>
errors: ComputedRef<AsyncValidatorError['errors'] | undefined>
errorInfo: ShallowRef<AsyncValidatorError | null>
errorFields: ComputedRef<AsyncValidatorError['fields'] | undefined>
execute: () => Promise<UseAsyncValidatorExecuteReturn>
}
各返回值的实际用途:
| 返回值 | 响应式类型 | 含义与典型场景 |
|---|---|---|
pass |
ShallowRef<boolean> |
校验是否通过;模板中直接控制提交按钮 disabled |
isFinished |
ShallowRef<boolean> |
本轮校验是否结束;配合异步校验规则区分「校验中」与「完成」状态 |
errors |
ComputedRef<ValidateError[]> |
错误数组,用于遍历渲染所有错误提示 |
errorFields |
ComputedRef<Record<string, ValidateError[]>> |
按字段分组的错误对象,便于字段级提示 |
errorInfo |
ShallowRef<AsyncValidatorError | null> |
最近一次校验的完整错误信息对象(含 errors 与 fields),无错误时为 null |
execute() |
函数 | 手动触发一次校验并返回 UseAsyncValidatorExecuteReturn(可 await) |
由于返回值满足 PromiseLike,await useAsyncValidator(...) 会得到一次校验后的结果对象,适合在非模板场景(如提交回调中)快速做一次性校验。
声明式规则与响应式联动
规则 rules 完全沿用 async-validator 的 descriptor 格式,常用内建约束包括:
const rules = {
username: [
{ required: true, message: '请输入用户名' },
{ min: 3, max: 20, message: '长度需在 3~20 之间' },
],
email: { type: 'email', required: true, message: '请输入合法邮箱' },
age: { type: 'number', min: 18, max: 99, message: '年龄超出范围' },
url: { type: 'url', message: 'URL 格式不合法' },
}
value 与 rules 的 MaybeRefOrGetter 支持意味着两种常见联动方式都是合法的:
// 1) 直接传 reactive 对象:数据变化即重校验
const form = reactive({ ... })
useAsyncValidator(form, rules)
// 2) 传 getter:按需读取最新值
useAsyncValidator(
() => ({ password: form.password, confirm: form.confirm }),
{
confirm: {
validator: (_rule, value) =>
value === form.password ? Promise.resolve() : Promise.reject('两次密码不一致'),
},
},
)
后者尤其适合处理「两次密码一致」这类跨字段校验——自定义 validator 函数返回 Promise,正是 async-validator 异步能力的核心用法,useAsyncValidator 会将其结果纳入 pass / errorInfo 状态。
典型实战场景:注册表单提交校验
综合上述能力,一个完整的手动校验 + 自动状态联动的注册表单可以这样组织:
<script setup lang="ts">
import { reactive, ref } from 'vue'
import { useAsyncValidator } from '@vueuse/integrations/useAsyncValidator'
const form = reactive({ username: '', email: '', password: '' })
const rules = {
username: { required: true, min: 3, message: '用户名至少 3 个字符' },
email: { type: 'email', required: true, message: '邮箱格式不正确' },
password: { required: true, min: 8, message: '密码至少 8 位' },
}
// 自动校验 + 手动可重触发
const { pass, errorFields, execute } = useAsyncValidator(
form, rules, { immediate: false, manual: true },
)
const submitting = ref(false)
async function handleSubmit() {
const result = await execute()
if (!result.pass) {
// 按字段展示错误:errorFields.value.username
return
}
submitting.value = true
// ...调用业务接口
}
</script>
<template>
<input v-model="form.username" />
<p v-for="e in errorFields.username" :key="e.message">{{ e.message }}</p>
<button :disabled="!pass || submitting" @click="handleSubmit">提交</button>
</template>
要点:errorFields 为字段分组错误,可直接按字段名取数组渲染;pass 作为 ShallowRef 在模板中自动解包,无需 .value。
仓库中的集成位置与使用约束
- 技能归属:
useAsyncValidator收录在 airi 的.agents/skills/vueuse-functions/references/useAsyncValidator.md,该技能库是面向 Vue 3 / Nuxt 3 开发决策的指南,由vendor/vueuse/skills/vueuse-functions同步而来(同步 SHAb6bb79b99fb1f1dba1f907829676a651735bbc10,见 SYNC.md)。 - 依赖版本:仓库锁文件确认
@vueuse/integrations@14.4.0存在且async-validator为其可选 peer 依赖(peerDependenciesMeta中 optional),说明该函数在 airi 中属于「按需启用」能力,需要时通过pnpm add async-validator@^4激活(pnpm-lock.yaml)。 - EXTERNAL 调用规则:按 SKILL.md 的约定,
useAsyncValidator归类为@Integrations且调用规则为EXTERNAL,即仅当依赖已安装时才建议引入;若业务仅需同步校验,应先考虑内建逻辑而非额外引入该集成。
注意事项
async-validator@^4与@vueuse/integrations的 peer 范围必须匹配:仓库锁文件显示@vueuse/integrations@14.4.0要求async-validator: ^4,安装过低或过主版本可能导致类型不匹配。validateOption的可用字段随 async-validator 版本变化,以实际安装版本的类型声明为准。immediate默认true:若不想在页面加载时立即弹错,请显式设置immediate: false或manual: true。- 校验目标是
Record<string, any>:数组或嵌套结构需在规则中通过type: 'array'/type: 'object'及fields描述,或自行扁平化为对象后再传入。