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

基于Vuelidate的Vue3单表单登录与注册校验问题

Vue3 + Vuelidate 实现登录/注册表单分场景校验

针对登录、注册共用表单且重叠字段需分场景校验的需求,你可以通过以下两种方式实现:

方式一:动态生成校验规则

通过计算属性根据当前表单模式(登录/注册)动态生成校验规则集合,Vuelidate会自动响应模式切换并更新校验逻辑。

代码示例

import { useVuelidate } from '@vuelidate/core'
import { required, email, minLength, sameAs } from '@vuelidate/validators'
import { ref, computed } from 'vue'

export default {
  setup() {
    // 控制当前表单模式:login/register
    const mode = ref('login')
    const form = ref({
      username: '',
      email: '',
      password: '',
      confirmPassword: ''
    })

    // 根据mode动态生成校验规则
    const validationRules = computed(() => {
      const baseRules = {
        email: {
          required: required,
          email: email,
          // 注册模式下可添加额外校验,比如异步校验邮箱唯一性
          ...(mode.value === 'register' && {
            isUnique: {
              $validator: async (val) => await checkEmailExists(val),
              $message: '该邮箱已被注册'
            }
          })
        },
        password: {
          required: required,
          // 登录模式要求密码至少6位,注册模式要求至少8位
          minLength: minLength(mode.value === 'register' ? 8 : 6)
        }
      }

      // 注册模式下追加专属字段规则
      if (mode.value === 'register') {
        return {
          ...baseRules,
          username: { required: required, minLength: minLength(3) },
          confirmPassword: { required: required, sameAs: sameAs(form.value.password) }
        }
      }

      return baseRules
    })

    const v$ = useVuelidate(validationRules, form)

    // 提交处理
    const handleSubmit = async () => {
      const isValid = await v$.value.validate()
      if (!isValid) return

      if (mode.value === 'login') {
        // 执行登录接口请求
        console.log('登录:', form.value.email, form.value.password)
      } else {
        // 执行注册接口请求
        console.log('注册:', form.value.username, form.value.email, form.value.password)
      }
    }

    return { mode, form, v$, handleSubmit }
  }
}

方式二:给校验规则添加生效条件

给每个校验规则配置$condition属性,仅当当前模式匹配时才触发该规则校验,适合规则差异较小的场景。

代码示例

import { useVuelidate } from '@vuelidate/core'
import { required, email, minLength, sameAs } from '@vuelidate/validators'
import { ref } from 'vue'

export default {
  setup() {
    const mode = ref('login')
    const form = ref({
      username: '',
      email: '',
      password: '',
      confirmPassword: ''
    })

    const validationRules = {
      email: {
        required: required,
        email: email,
        // 仅注册模式下校验邮箱唯一性
        isUnique: {
          $validator: async (val) => await checkEmailExists(val),
          $message: '该邮箱已被注册',
          $condition: () => mode.value === 'register'
        }
      },
      password: {
        required: required,
        // 登录模式下密码至少6位
        minLengthLogin: {
          $validator: minLength(6),
          $message: '密码至少6位',
          $condition: () => mode.value === 'login'
        },
        // 注册模式下密码至少8位
        minLengthRegister: {
          $validator: minLength(8),
          $message: '密码至少8位',
          $condition: () => mode.value === 'register'
        }
      },
      username: {
        required: {
          $validator: required,
          $condition: () => mode.value === 'register'
        },
        minLength: {
          $validator: minLength(3),
          $condition: () => mode.value === 'register'
        }
      },
      confirmPassword: {
        required: {
          $validator: required,
          $condition: () => mode.value === 'register'
        },
        sameAsPassword: {
          $validator: sameAs(form.value.password),
          $message: '两次输入的密码不一致',
          $condition: () => mode.value === 'register'
        }
      }
    }

    const v$ = useVuelidate(validationRules, form)

    const handleSubmit = async () => {
      const isValid = await v$.value.validate()
      if (!isValid) return

      // 区分模式执行对应逻辑
      mode.value === 'login' 
        ? console.log('登录请求') 
        : console.log('注册请求')
    }

    return { mode, form, v$, handleSubmit }
  }
}

模板层字段控制

在模板中通过v-if根据mode控制字段显示:

<template>
  <div class="auth-modal">
    <div class="mode-switch">
      <button @click="mode = 'login'" :class="{ active: mode === 'login' }">登录</button>
      <button @click="mode = 'register'" :class="{ active: mode === 'register' }">注册</button>
    </div>

    <form @submit.prevent="handleSubmit">
      <!-- 用户名:仅注册模式显示 -->
      <div v-if="mode === 'register'" class="form-group">
        <label>用户名</label>
        <input v-model="form.username" type="text" />
        <span class="error" v-if="v$.username.$error">{{ v$.username.$errors[0].$message }}</span>
      </div>

      <!-- 邮箱:两种模式都显示 -->
      <div class="form-group">
        <label>邮箱</label>
        <input v-model="form.email" type="email" />
        <span class="error" v-if="v$.email.$error">{{ v$.email.$errors[0].$message }}</span>
      </div>

      <!-- 密码:两种模式都显示 -->
      <div class="form-group">
        <label>密码</label>
        <input v-model="form.password" type="password" />
        <span class="error" v-if="v$.password.$error">{{ v$.password.$errors[0].$message }}</span>
      </div>

      <!-- 重复密码:仅注册模式显示 -->
      <div v-if="mode === 'register'" class="form-group">
        <label>重复密码</label>
        <input v-model="form.confirmPassword" type="password" />
        <span class="error" v-if="v$.confirmPassword.$error">{{ v$.confirmPassword.$errors[0].$message }}</span>
      </div>

      <button type="submit" class="submit-btn">{{ mode === 'login' ? '登录' : '注册' }}</button>
    </form>
  </div>
</template>

内容的提问来源于stack exchange,提问作者Yavor

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.10 13:00:35