Vuetify 表单组件 VForm 完全指南:内置校验规则、验证时机与状态控制实战
【免费下载链接】vuetify🐉 Vue Component Framework项目地址: https://gitcode.com/gh_mirrors/vu/vuetify
Vuetify 的v-form组件提供了一套内置于框架的、基于"函数即规则(functions as rules)"的简单表单校验体系,开发者无需引入额外依赖即可完成输入校验、错误展示与提交拦截。本文以官方文档为骨架,结合仓库源码(VForm.tsx、form.ts、validation.ts)深入讲解规则编写、validate-on验证时机控制、验证状态三态模型,以及disabled、fast-fail、组件暴露方法(validate()/reset()/resetValidation())等实战要点,并给出与 Vee-validate、Vuelidate 集成的参考方案,帮助你在 Vue 3 + Vuetify 项目中快速落地可靠的表单校验。
快速上手:使用 v-form 为输入组件添加校验
v-form组件为表单输入提供了一个统一的校验包装器。所有输入组件(如v-text-field、v-select、v-checkbox等)都支持rulesprop,用来指定该输入是valid还是invalid的条件:
<v-form v-model="valid"> <v-text-field v-model="firstname" :counter="10" :rules="nameRules" label="First name" required ></v-text-field> <v-text-field v-model="email" :rules="emailRules" label="E-mail" required ></v-text-field> </v-form>每当输入值发生变化时,每条规则都会收到新的值并被重新评估。如果某条规则返回false或一个string,则代表校验失败,该string会被作为错误信息展示给用户;返回true则代表该校验通过。完整的可运行示例位于 packages/docs/src/examples/v-form/usage.vue,其中包含"必填 + 长度上限"与"必填 + 邮箱格式"两组典型规则:
nameRules: [ value => { if (value) return true return 'Name is required.' }, value => { if (value?.length <= 10) return true return 'Name must be less than 10 characters.' }, ], emailRules: [ value => { if (value) return true return 'E-mail is required.' }, value => { if (/.+@.+\..+/.test(value)) return true return 'E-mail must be valid.' }, ],组件级 API 以v-form为核心(其组件注册与导出位于 packages/vuetify/src/components/VForm/index.ts,完整 props 定义见 VForm.tsx 中的makeVFormProps)。如果你更习惯第三方校验插件,官方也提供了 Vee-validate 与 Vuelidate 的集成示例(见下文"与第三方校验库集成")。
深入 Rules:从必填到异步校验
规则(Rules)允许你在所有表单组件上施加自定义校验。它们按顺序依次验证,且组件同一时刻最多只显示 1 条错误(maxErrors默认值为 1,见 validation.ts 中makeValidationProps的定义)。因此请务必按照优先级排列你的规则,把最重要的规则放在最前面。
最基本的规则:必填校验
最简单的规则就是一个检查输入是否有值的函数,即把它变成一个必填输入:
<v-text-field v-model="name" :rules="[v => !!v || 'Name is required']" label="Name" ></v-text-field>官方示例 rules-required.vue 展示了多条规则叠加的效果。
规则别名:内置的常用校验函数
除了手写函数,Vuetify 还提供了一套**规则别名(aliases)**系统。在 rules/rules.ts 中内置了required、email、number、integer、capital、maxLength、minLength、strictLength、exclude、notEmpty、pattern等构建器,你可以直接在rulesprop 中以字符串或[别名, 参数, 自定义错误]元组的形式使用,例如:rules="['required', 'email']"或:rules="[['maxLength', 10, 'Too long']]"。这些别名同样支持传入自定义错误文案,未传入时会回退到对应语言包中的默认文案。
异步规则:对接 API 的校验
规则可以做得非常复杂,甚至支持异步输入校验。在示例 rules-async.vue 中,输入会对照一个模拟的 API 服务进行校验——该服务需要约 1 秒的响应时间。其核心规则是一个返回 Promise 的校验函数:
<v-form validate-on="submit lazy" @submit.prevent="submit"> <v-text-field v-model="userName" :rules="rules" label="User name" ></v-text-field> <v-btn :loading="loading" class="mt-2" text="Submit" type="submit" block></v-btn> </v-form>const rules = [value => checkApi(value)] async function checkApi (userName) { return new Promise(resolve => { setTimeout(() => { if (!userName) return resolve('Please enter a user name.') if (userName === 'johnleider') return resolve('User name already taken. Please try another one.') return resolve(true) }, 1000) }) } async function submit (event) { loading.value = true const results = await event // submit 事件是一个可 await 的 Promise loading.value = false alert(JSON.stringify(results, null, 2)) }这里的关键点有两个:
- submit 事件是可等待的 Promise:
submit事件是原生SubmitEvent与一个 Promise 的组合(SubmitEventPromise,类型定义见 form.ts),因此可以直接await或使用.then()拿到校验结果。在 VForm.tsx 的onSubmit处理中,事件对象被绑定上then/catch/finally,并只有在校验通过(valid === true)且未调用preventDefault时才会真正提交原生表单。 - validate-on prop 控制验证时机:这里设置为
'submit lazy',表示只在点击按钮(触发提交)时才去调用 API 服务,避免每次输入都发起远程校验请求。
验证时机控制:validate-on 与验证状态模型
validate-on 支持的值与行为矩阵
何时运行规则由validate-onprop 控制,它接受一个字符串,其中可包含input、blur、submit、invalid-input、eager或lazy:
input、blur、submit、eager决定了校验错误最早可以在何时展示给用户;lazy则在挂载时禁用校验(对异步规则尤其有用)。
默认情况下,所有输入组件在挂载时都会运行各自的校验规则,但不会向用户展示错误。加上eager会在挂载后立即展示错误,加上lazy则连挂载时的校验也一并禁用。
eager和lazy可以与其他选项组合使用,但二者不能互相组合;单独使用时,二者都隐含input行为。invalid-input的行为与blur相同,唯一的例外是:一旦字段处于 invalid 状态,它就会改为在input时校验,直到校验重新通过为止。
validate-on= | "input" | "blur" | "submit" | "invalid-input" | "eager" | "lazy" |
|---|---|---|---|---|---|---|
| On mount | ✅ | ✅ | ✅ | ✅ | ✅† | ❌ |
| On input | ✅ | ❌ | ❌ | ‡ | * | * |
| On blur | ✅ | ✅ | ❌ | ✅ | * | * |
| On submit | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
- * 遵循与其组合项相同的行为,默认等同于
on="input"。 - † 在挂载或重置时立即展示错误。
- ‡ 仅当此前校验已失败时。
这一套解析逻辑在 validation.ts 的validateOncomputed 中实现:单独的'lazy'会被展开为'input lazy'、'eager'被展开为'input eager',随后按空格拆分并建立input/blur/invalidInput/lazy/eager五个布尔开关。blur额外包含了input与invalid-input的隐含关系——这正对应表格中"On blur"列的行为。另外,v-form本身也有validateOnprop(默认'input',见 form.ts),作为其内部所有输入组件的默认值,单个输入组件可以通过自己的validate-on覆盖它。
表单校验状态的三种取值
表单当前的校验状态可以通过v-model或 submit 事件获取,它只有三种取值:
true:所有带校验规则的输入都已成功通过校验。false:至少一个输入因交互或手动校验而校验失败。null:至少一个输入未经交互即校验失败,或由于lazy校验尚未被验证。
从源码角度看,这个三态模型由 form.ts 中watch(items)的逻辑直接决定:只要存在isValid === false的字段即为false;当所有字段均为true时为true;其余情况(存在尚未验证或未经交互的失败字段)为null。
据此,你可以用!valid检查是否存在任何校验失败,或用valid === false只检查当前已展示给用户的错误:
if (!valid) { // 存在校验失败(包括尚未展示给用户的) } if (valid === false) { // 存在已经展示给用户的错误 }实战示例与属性详解
一键禁用:disabled prop
通过给v-form设置disabledprop,可以一次性禁用表单内所有输入组件:
<v-form disabled> <!-- 内部所有输入组件全部变为禁用态 --> </v-form>其实现本质是v-form通过 provide/inject 向所有注册的输入组件传递isDisabled状态(见 form.ts 中的useForm,它会合并props.disabled与父表单的form.isDisabled),从而使每个输入组件自动应用禁用样式与禁用交互。完整示例见 prop-disabled.vue。
快速失败:fast-fail prop
当设置fast-failprop 时,校验会在找到第一个无效输入后短路,不再继续校验后续输入。如果你的部分规则计算量很大、耗时较长,这会非常有用。官方示例 prop-fast-fail.vue 中,点击提交后第二个输入即使不满足规则也不会显示校验错误——因为在 form.ts 的createForm.validate()中,遍历到第一个校验失败的字段且props.fastFail为真时就会break退出循环:
for (const item of items.value) { const itemErrorMessages = await item.validate() if (itemErrorMessages.length > 0) { valid = false results.push({ id: item.id, errorMessages: itemErrorMessages }) } if (!valid && props.fastFail) break }暴露的方法:validate()、reset() 与 resetValidation()
v-form组件暴露了一系列内部方法,可以通过给组件设置ref来访问(组件通过forwardRefs将form的内部方法转发到组件实例上,见 VForm.tsx)。其中使用频率最高的是validate()、reset()和resetValidation(),完整列表可在 API 页面查阅:
validate():手动触发校验,返回Promise<{ valid, errors }>;reset():同时重置输入值与校验状态;resetValidation():仅重置校验状态,不影响输入值。
官方示例 misc-exposed.vue 用三个按钮演示了它们的区别。其底层实现位于 validation.ts:
async function reset () { isResetting = true model.value = null // ① 清空输入值 await nextTick() isResetting = false await resetValidation() // ② 再重置校验状态 } async function resetValidation () { isPristine.value = true if (!validateOn.value.lazy) { await validate(!validateOn.value.eager) // 重新运行规则但不展示错误 } else { internalErrorMessages.value = [] // lazy 模式下直接清空错误 } }值得注意的是validate(silent)中的silent参数:默认校验(如提交时)为silent = false,会同步设置isPristine,从而把校验结果纳入valid === false的判断;而挂载时与重置时以silent = true调用,保证"未交互不展示错误"的默认体验。另外,validate()内部会顺序执行所有规则,并通过maxErrors截断错误列表(results.length >= Number(props.maxErrors ?? 1)时提前终止),这也是"最多显示 1 条错误"的根源。
与第三方校验库集成
如果你更偏好成熟的第三方校验方案,Vuetify 同样可以与之无缝配合:
- Vee-validate:官方示例 misc-vee-validate.vue 展示了将 Vee-validate v4 的
useField/useForm与v-form及输入组件结合使用的模式,通过rulesprop 传入 Vee-validate 生成的校验函数。 - Vuelidate:官方示例 misc-vuelidate.vue 展示了将 Vuelidate 的
v$状态映射到输入组件校验规则(如:rules="[v => !v$.value.email.$invalid || v$.value.email.$message]")的集成方式。
两种方案都保留了对错误文案、异步校验和复杂跨字段规则的完整支持。
小结
v-form是 Vuetify 中处理表单校验的核心组件:它以"函数即规则"的极简设计覆盖了从必填、格式校验到异步远程校验的绝大多数场景,通过validate-on精确控制校验时机,用三态v-model表达表单的完整校验状态,并提供disabled、fast-fail与validate()/reset()/resetValidation()等实用能力。若需要与 Vee-validate、Vuelidate 等生态库协同,官方示例也给出了可直接落地的参考代码。建议在实际项目中结合 validation.ts 与 form.ts 的源码理解其行为边界,从而写出更稳健的表单交互。
【免费下载链接】vuetify🐉 Vue Component Framework项目地址: https://gitcode.com/gh_mirrors/vu/vuetify
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考