11 - 构建表单验证系统
时长:15 分钟
视频信息
- 标题:构建表单验证系统
- 系列:实战系列
- 难度:中级
- 前置知识:Vue 表单基础、Composables
章节目录
- 需求分析与设计(2 分钟)
- 表单结构搭建(3 分钟)
- 实时验证实现(4 分钟)
- 提交处理与反馈(3 分钟)
- 优化与扩展(3 分钟)
详细脚本
开场(0:00-0:15)
今天我们通过一个实际案例,演示如何使用 Directix 构建一个完整的表单验证系统。
第一章:需求分析与设计(0:15-2:15)
画面:展示表单原型
我们要创建一个用户注册表单,包含:
- 姓名(必填,首字母大写)
- 邮箱(必填,格式验证)
- 手机号(格式化显示,验证)
- 密码(强度验证)
- 确认密码(匹配验证)
- 提交按钮(防抖、节流)
使用到的指令:
v-trim- 去除空格v-capitalcase- 首字母大写v-lowercase- 邮箱小写v-mask- 手机号格式化v-debounce- 实时验证防抖v-throttle- 提交节流v-focus- 错误字段聚焦
第二章:表单结构搭建(2:15-5:15)
画面:VS Code 演示
vue
<template>
<form @submit.prevent="handleSubmit" class="register-form">
<!-- 姓名 -->
<div class="form-group">
<label>姓名</label>
<input
v-model="form.name"
v-trim
v-capitalcase
v-debounce:300="validateName"
:class="{ error: errors.name }"
placeholder="请输入姓名"
/>
<span v-if="errors.name" class="error-msg">{{ errors.name }}</span>
</div>
<!-- 邮箱 -->
<div class="form-group">
<label>邮箱</label>
<input
v-model="form.email"
v-trim
v-lowercase
v-debounce:300="validateEmail"
type="email"
:class="{ error: errors.email }"
placeholder="请输入邮箱"
/>
<span v-if="errors.email" class="error-msg">{{ errors.email }}</span>
</div>
<!-- 手机号 -->
<div class="form-group">
<label>手机号</label>
<input
v-model="form.phone"
v-mask="'### #### ####'"
v-debounce:300="validatePhone"
:class="{ error: errors.phone }"
placeholder="请输入手机号"
/>
<span v-if="errors.phone" class="error-msg">{{ errors.phone }}</span>
</div>
<!-- 密码 -->
<div class="form-group">
<label>密码</label>
<input
v-model="form.password"
v-debounce:300="validatePassword"
type="password"
:class="{ error: errors.password }"
placeholder="请输入密码"
/>
<div class="password-strength">
<div :class="['bar', strength]"></div>
<span>{{ strengthText }}</span>
</div>
</div>
<!-- 确认密码 -->
<div class="form-group">
<label>确认密码</label>
<input
v-model="form.confirmPassword"
v-debounce:300="validateConfirmPassword"
type="password"
:class="{ error: errors.confirmPassword }"
placeholder="请再次输入密码"
/>
<span v-if="errors.confirmPassword" class="error-msg">
{{ errors.confirmPassword }}
</span>
</div>
<!-- 提交按钮 -->
<button
type="submit"
v-throttle:1000="handleSubmit"
:disabled="!isFormValid || submitting"
>
{{ submitting ? '提交中...' : '注册' }}
</button>
</form>
</template>第三章:实时验证实现(5:15-9:15)
画面:展示验证逻辑
vue
<script setup>
import { ref, reactive, computed } from 'vue'
import { useDebounce } from 'directix'
// 表单数据
const form = reactive({
name: '',
email: '',
phone: '',
password: '',
confirmPassword: ''
})
// 错误信息
const errors = reactive({
name: '',
email: '',
phone: '',
password: '',
confirmPassword: ''
})
// 验证规则
const validators = {
name: (value) => {
if (!value) return '请输入姓名'
if (value.length < 2) return '姓名至少2个字符'
return ''
},
email: (value) => {
if (!value) return '请输入邮箱'
if (!/^[\w.-]+@[\w.-]+\.\w+$/.test(value)) return '邮箱格式不正确'
return ''
},
phone: (value) => {
const cleaned = value.replace(/\s/g, '')
if (!cleaned) return '请输入手机号'
if (!/^1[3-9]\d{9}$/.test(cleaned)) return '手机号格式不正确'
return ''
},
password: (value) => {
if (!value) return '请输入密码'
if (value.length < 8) return '密码至少8位'
if (!/[A-Z]/.test(value)) return '需包含大写字母'
if (!/[0-9]/.test(value)) return '需包含数字'
return ''
},
confirmPassword: (value) => {
if (!value) return '请确认密码'
if (value !== form.password) return '两次密码不一致'
return ''
}
}
// 验证函数
const validateName = () => { errors.name = validators.name(form.name) }
const validateEmail = () => { errors.email = validators.email(form.email) }
const validatePhone = () => { errors.phone = validators.phone(form.phone) }
const validatePassword = () => {
errors.password = validators.password(form.password)
updateStrength()
}
const validateConfirmPassword = () => {
errors.confirmPassword = validators.confirmPassword(form.confirmPassword)
}
// 密码强度
const strength = ref('weak')
const strengthText = computed(() => {
const map = { weak: '弱', medium: '中', strong: '强' }
return map[strength.value]
})
const updateStrength = () => {
const pwd = form.password
let score = 0
if (pwd.length >= 8) score++
if (/[A-Z]/.test(pwd)) score++
if (/[a-z]/.test(pwd)) score++
if (/[0-9]/.test(pwd)) score++
if (/[^A-Za-z0-9]/.test(pwd)) score++
strength.value = score <= 2 ? 'weak' : score <= 4 ? 'medium' : 'strong'
}
// 表单是否有效
const isFormValid = computed(() => {
return Object.values(errors).every(e => e === '')
&& Object.values(form).every(v => v !== '')
})
const submitting = ref(false)
</script>第四章:提交处理与反馈(9:15-12:15)
画面:展示提交逻辑
vue
<script setup>
// ... 之前的代码
// 全局验证
const validateAll = () => {
validateName()
validateEmail()
validatePhone()
validatePassword()
validateConfirmPassword()
return isFormValid.value
}
// 聚焦到第一个错误字段
const focusFirstError = () => {
const firstError = Object.keys(errors).find(key => errors[key])
if (firstError) {
const input = document.querySelector(`[v-model="form.${firstError}"]`)
if (input) input.focus()
}
}
// 提交处理
const handleSubmit = async () => {
if (!validateAll()) {
focusFirstError()
return
}
submitting.value = true
try {
// 清理手机号空格
const data = {
...form,
phone: form.phone.replace(/\s/g, '')
}
await api.register(data)
showToast('注册成功!')
// 跳转到登录页
router.push('/login')
} catch (error) {
showToast(error.message || '注册失败,请重试')
} finally {
submitting.value = false
}
}
</script>第五章:优化与扩展(12:15-15:00)
画面:展示优化代码
1. 使用 useDebounce 优化:
vue
<script setup>
import { useDebounce } from 'directix'
// 将验证函数转为防抖函数
const debouncedValidateName = useDebounce(validateName, 300)
</script>
<template>
<input @input="debouncedValidateName" />
</template>2. 添加实时保存:
vue
<script setup>
import { useDebounce } from 'directix'
// 自动保存草稿
const { debouncedValue } = useDebounce(form, 1000)
watch(debouncedValue, () => {
localStorage.setItem('register-draft', JSON.stringify(form))
})
</script>3. 添加复制功能:
vue
<template>
<div class="form-group">
<label>邀请码</label>
<div class="input-group">
<input v-model="inviteCode" readonly />
<button v-copy="inviteCode">复制</button>
</div>
</div>
</template>总结
今天我们完成了一个完整的表单验证系统:
- 使用多个指令组合实现功能
- 实时验证与错误提示
- 密码强度检测
- 提交节流防重复
- 用户体验优化
下集我们实现无限滚动列表。
练习题
- 为表单添加验证码输入框,使用 v-mask 格式化
- 实现表单数据本地存储,刷新后恢复
- 添加提交成功的动画效果