如何用Vuelidate的Or验证器实现手机号/邮箱二选一必填?
Vue + Vuelidate 实现“邮箱/手机号至少填一个”的验证
你的理解完全正确
Or验证器的核心逻辑就是:只要邮箱或手机号任意一个填写(若有格式要求则需同时通过格式验证),整体验证就通过;只有当两个字段都为空时,验证才会失败。
你的代码错误原因
你写的or(phone)报错“phone not defined”,问题出在两点:
- 直接引用
phone无法访问到form对象里的字段,Vuelidate需要通过函数上下文来获取其他字段的值 - 你把跨字段的联合验证逻辑放在了单个字段(email)的规则里,这不符合逻辑——“至少填一个”是针对整个表单的约束,不是单个字段的约束。
正确实现方案
1. 先确认导入所需验证器
确保你已经从@vuelidate/validators导入需要的工具:
import { required, or, helpers } from '@vuelidate/validators'
2. 在表单层级添加联合验证
把“至少填一个”的规则放在form对象下,通过函数上下文获取两个字段的值:
data: () => ({ form: { email: '', phone: '', }, }), validations: { form: { // 跨字段联合验证:至少填写一个 atLeastOne: helpers.withParams( { message: '邮箱和手机号至少填写一个' }, ({ form }) => or( () => !!form.email, // 邮箱不为空 () => !!form.phone // 手机号不为空 ) ), // 单个字段的可选格式验证(按需添加) email: { email: helpers.withParams({ message: '请输入正确的邮箱格式' }, true) }, phone: { // 示例:手机号格式验证(自定义正则) validPhone: helpers.withParams( { message: '请输入正确的手机号格式' }, (value) => /^1[3-9]\d{9}$/.test(value) ) } } }
3. 如果需要结合“必填”和格式验证
要是你希望:填了邮箱就要格式正确,填了手机号就要格式正确,且至少填一个,可以调整联合验证逻辑:
validations: { form: { atLeastOneValid: helpers.withParams( { message: '请填写有效的邮箱或手机号' }, ({ form }) => or( () => form.email && v$.form.email.email.$valid, () => form.phone && v$.form.phone.validPhone.$valid ) ), // 单个字段规则同上 email: { email: true }, phone: { validPhone: (value) => /^1[3-9]\d{9}$/.test(value) } } }
4. 模板中显示错误提示
在模板里要针对表单层级的联合验证错误进行提示,同时保留单个字段的错误提示:
<template> <div class="form-container"> <div class="form-group"> <label>邮箱</label> <input v-model="form.email" type="email" placeholder="请输入邮箱"> <span class="error" v-if="v$.form.email.email.$error"> {{ v$.form.email.email.$message }} </span> </div> <div class="form-group"> <label>手机号</label> <input v-model="form.phone" type="tel" placeholder="请输入手机号"> <span class="error" v-if="v$.form.phone.validPhone.$error"> {{ v$.form.phone.validPhone.$message }} </span> </div> <!-- 联合验证错误提示 --> <span class="error" v-if="v$.form.atLeastOne.$error"> {{ v$.form.atLeastOne.$message }} </span> <button @click="handleSubmit" :disabled="v$.form.$invalid">提交</button> </div> </template> <script setup> import { useVuelidate } from '@vuelidate/core' import { required, or, helpers } from '@vuelidate/validators' import { reactive } from 'vue' const form = reactive({ email: '', phone: '' }) const validations = { form: { atLeastOne: helpers.withParams( { message: '邮箱和手机号至少填写一个' }, ({ form }) => or( () => !!form.email, () => !!form.phone ) ), email: { email: helpers.withParams({ message: '请输入正确的邮箱格式' }, true) }, phone: { validPhone: helpers.withParams( { message: '请输入正确的手机号格式' }, (value) => /^1[3-9]\d{9}$/.test(value) ) } } } const v$ = useVuelidate(validations, { form }) const handleSubmit = () => { v$.value.$validate() if (!v$.value.$invalid) { // 提交逻辑 console.log('表单验证通过,提交数据:', form) } } </script>
关键注意点
- 跨字段验证必须放在父级(这里是
form)的验证规则里,不能放在单个字段下 - 使用
helpers.withParams可以自定义错误提示信息,提升用户体验 - 如果用
<script setup>语法,要确保正确使用useVuelidate并关联表单数据
内容的提问来源于stack exchange,提问作者Luka
相关产品推荐
相关产品推荐

