You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何创建非阻塞式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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.29 00:27:01