如何创建非阻塞式Vuelidate自定义验证器
问题:Vuelidate自定义验证器不影响表单整体校验结果
我在使用Vuelidate时遇到一个需求:希望给邮箱字段添加验证规则(比如邮箱格式校验),但即便这个字段验证失败,调用$validate()或$touch()时也不会让整个表单的校验结果返回false,同时错误信息还要正常显示在v$.email.$errors数组中。
当前的表单组件代码如下:
<template> <div> <InputCommon id="client-name" :label="$t('client.form.name')" required v-model="store.form.client.name" :error="v$.name.$errors[0]" /> <InputCommon id="client-email" :label="$t('client.form.email')" v-model="store.form.client.email" :error="v$.email.$errors[0]" /> </div> </template> <script setup lang="ts"> import InputCommon from "@/components/common/inputs/InputCommon.vue"; import { useStore } from "@/store/store"; import { onMounted } from "vue"; import { useVuelidate } from "@vuelidate/core"; import { computed } from "vue"; import { required, email } from "@vuelidate/validators"; const rules = computed(() => { return { name: { required }, email: { email } // 希望这个验证失败不影响整体校验返回值 }; }); const store = useStore(); const v$ = useVuelidate(rules, store.form.client); // 如果validate返回false,表单无法提交 async function validate() { let validation = await v$.value.$validate(); return validation; } function reset() { v$.value.$reset(); } onMounted(() => { if (!store.form.client) { store.form.client = { name: "", email: "", }; } else { validate(); } }); defineExpose({ validate, reset }); </script>
我试过手动校验并往错误数组里加ErrorObject,但这种方法太繁琐且不灵活,想找更优雅的解决方案。
解决方案
方法一:重写validate函数,过滤非关键错误
直接修改现有的validate函数,先执行完整校验收集所有错误信息,再单独检查必填字段的校验状态来决定返回值:
async function validate() { // 先执行完整校验,确保所有错误信息都被收集到$errors中 await v$.value.$validate(); // 只检查必填字段的校验状态,忽略邮箱字段的错误 const requiredFieldsValid = v$.value.name.$dirty && !v$.value.name.$invalid; return requiredFieldsValid; }
如果有多个必填字段,可以统一遍历检查:
async function validate() { await v$.value.$validate(); // 筛选出所有带required规则的字段 const requiredFields = Object.keys(rules.value).filter(key => rules.value[key].required !== undefined ); // 检查所有必填字段是否都校验通过 const allRequiredValid = requiredFields.every(key => v$.value[key].$dirty ? !v$.value[key].$invalid : true ); return allRequiredValid; }
方法二:创建自定义"警告式"验证器
封装一个通用的包装函数,让原有验证器只收集错误但不标记字段为无效,适合复用场景:
import { email } from "@vuelidate/validators"; // 包装验证器,使其仅收集错误信息,不影响字段的$invalid状态 const warn = (validator) => { return (value) => { const result = validator(value); if (result !== true) { return { $invalid: false, // 强制标记为有效,不影响整体校验结果 $message: typeof result === 'string' ? result : result.$message }; } return true; }; }; // 使用包装后的验证器 const rules = computed(() => { return { name: { required }, email: { email: warn(email) } }; });
这样修改后,邮箱字段验证失败时,错误信息会正常加入$errors数组,但不会让字段的$invalid变为true,因此整个表单的$validate()返回值只会由必填字段的状态决定。
内容的提问来源于stack exchange,提问作者straut
相关产品推荐
相关产品推荐

