基于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
相关产品推荐
相关产品推荐

