1. 为什么需要可扩展的表单验证框架
在Web应用开发中,表单验证是保证数据完整性和用户体验的关键环节。传统的验证方式往往存在几个痛点:验证逻辑分散在各个组件中难以维护、不同表单的验证规则无法复用、复杂的联动验证难以实现。这些问题在Vue3项目中尤为明显,因为Vue3的Composition API虽然提供了更好的逻辑复用能力,但如果没有良好的架构设计,验证代码反而更容易变得混乱。
我最近重构了一个电商后台管理系统,其中包含47种不同类型的表单。最初采用直接在组件内编写验证逻辑的方式,结果发现:
- 相同的手机号验证逻辑重复出现在12个不同组件中
- 修改一个基础验证规则需要同步修改多处
- 跨表单字段的联动验证(如选择"国际"时才需要填写护照号)难以实现
这促使我设计了一套基于Vue3的可扩展验证框架,核心目标是:
- 验证规则与组件解耦
- 支持规则动态组合
- 提供友好的开发者体验
- 保持高性能
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 核心架构设计
2.1 分层设计
整个验证系统分为四个层次:
- 规则层:最基础的验证规则单元
- 组合层:将多个规则组合成验证策略
- 连接层:将验证策略绑定到表单字段
- 反馈层:处理验证结果展示
typescript复制// 典型的使用示例
const { validate } = useFormValidation({
username: [required(), minLength(5), maxLength(20)],
password: [
required(),
complexPassword({
min: 8,
requireSpecialChar: true
})
]
})
2.2 规则设计原则
每个验证规则都是独立的函数,遵循以下原则:
- 纯函数设计:不依赖外部状态
- 返回标准化的验证结果对象
- 支持配置化参数
- 类型安全(TypeScript)
typescript复制interface ValidationResult {
isValid: boolean
message?: string
}
type Validator = (value: any, context?: any) => ValidationResult | Promise<ValidationResult>
function required(message = '必填字段'): Validator {
return (value) => ({
isValid: value !== undefined && value !== null && value !== '',
message
})
}
3. 关键技术实现
3.1 响应式验证引擎
利用Vue3的reactivity系统构建验证引擎核心:
typescript复制import { ref, computed, watchEffect } from 'vue'
function useFormValidation(fieldValidators) {
const fieldStates = Object.fromEntries(
Object.entries(fieldValidators).map(([field, validators]) => [
field,
{
value: ref(null),
errors: ref([]),
isValid: computed(() => !fieldStates[field].errors.value.length)
}
])
)
const validateAll = async () => {
const results = await Promise.all(
Object.entries(fieldValidators).map(async ([field, validators]) => {
const errors = []
for (const validator of validators) {
const result = await validator(fieldStates[field].value.value)
if (!result.isValid) errors.push(result.message)
}
fieldStates[field].errors.value = errors
return errors.length === 0
})
)
return results.every(Boolean)
}
return { fieldStates, validateAll }
}
3.2 动态规则注册
通过提供规则注册机制,允许在运行时添加新规则:
typescript复制const customValidators = new Map<string, Validator>()
function registerValidator(name: string, validator: Validator) {
if (customValidators.has(name)) {
console.warn(`Validator ${name} already exists`)
return
}
customValidators.set(name, validator)
}
function getValidator(name: string, ...args: any[]): Validator {
const validator = customValidators.get(name)
if (!validator) throw new Error(`Validator ${name} not found`)
return (value)
