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

如何用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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.18 15:15:36