阅读时间:1 分钟
0 字
useFormValidate
useFormValidate hook 专门用于表单数据验证,基于 vee-validate 的 validationSchema 构建。
功能特点
- ✅ 独立验证 - 可单独使用的表单验证功能
- 📝 响应式验证 - 表单数据变化时自动更新验证状态
- ⚡ 异步验证 - 支持异步验证函数(由 schema 支持)
- 🔄 状态重置 - 提供验证状态重置功能
- 🎯 错误详情 - 提供详细的验证错误信息
支持的验证方式
useValidateForm 通过 validationSchema 接收 TypedSchema(如 Yup/Zod)。
接口关系
该hook基于 vee-validate 构建,提供简化的验证接口。
typescript
// 参数接口
interface UseValidateFormProps {
data?: MaybeRef<Record<string, any>> // 要验证的表单数据
rules?: TypedSchema // 验证规则(支持字符串规则或 Yup Schema)
}
// 返回值接口
interface UseValidateFormReturn {
validate: () => Promise<ValidationResult> // 验证表单数据
reset: () => void // 重置验证状态
submit: Function // 处理表单提交(来自 vee-validate)
}
// 验证结果接口
interface ValidationResult {
valid: boolean // 是否验证通过
errors: Record<string, string> // 错误信息对象
}使用方法
js
import { useValidateForm } from '@duxweb/dvha-core'
import { ref } from 'vue'
import * as yup from 'yup'
const formData = ref({
name: '',
email: ''
})
const { validate, reset, submit } = useValidateForm({
data: formData,
rules: yup.object({
name: yup.string().required('姓名是必填的').min(2, '姓名至少2个字符'),
email: yup.string().required('邮箱是必填的').email('请输入有效邮箱')
})
})参数说明
| 参数 | 类型 | 必需 | 说明 |
|---|---|---|---|
data | MaybeRef<Record<string, any>> | ❌ | 要验证的表单数据 |
rules | TypedSchema | ❌ | 验证规则(schema) |
返回值
| 字段 | 类型 | 说明 |
|---|---|---|
validate | () => Promise<ValidationResult> | 验证表单数据 |
reset | () => void | 重置验证状态 |
submit | Function | 处理表单提交(来自 vee-validate) |
验证示例
js
import { useValidateForm } from '@duxweb/dvha-core'
import { ref } from 'vue'
import * as yup from 'yup'
const formData = ref({
username: '',
password: '',
confirmPassword: '',
email: '',
phone: '',
age: null
})
const { validate, reset } = useValidateForm({
data: formData,
rules: yup.object({
username: yup.string().required().min(3).max(20),
password: yup.string().required().min(6),
confirmPassword: yup.string().oneOf([yup.ref('password')]),
email: yup.string().required().email(),
phone: yup.string(),
age: yup.number().min(1).max(120)
})
})
async function handleValidate() {
const result = await validate()
if (result.valid) {
console.log('验证通过')
}
else {
console.log('验证失败:', result.errors)
}
}birthday: 'required|date_format:YYYY-MM-DD',
// 选择验证 status: 'required|one_of:active,inactive,pending' }
## 方式二:Yup Schema 验证示例
### 基础验证示例
```js
import { useValidateForm } from '@duxweb/dvha-core'
import { ref } from 'vue'
import * as yup from 'yup'
const formData = ref({
username: '',
password: '',
confirmPassword: '',
email: '',
phone: '',
age: null
})
const validationSchema = yup.object({
username: yup.string()
.required('用户名是必填的')
.min(3, '用户名至少3个字符')
.max(20, '用户名最多20个字符'),
password: yup.string()
.required('密码是必填的')
.min(6, '密码至少6个字符'),
confirmPassword: yup.string()
.required('请确认密码')
.oneOf([yup.ref('password')], '两次密码不一致'),
email: yup.string()
.required('邮箱是必填的')
.email('请输入有效邮箱'),
phone: yup.string()
.matches(/^1[3-9]\d{9}$/, '请输入有效手机号'),
age: yup.number()
.required('年龄是必填的')
.positive('年龄必须是正数')
.integer('年龄必须是整数')
.max(120, '年龄不能超过120岁')
})
const { validate, reset } = useValidateForm({
data: formData,
rules: validationSchema
})异步验证示例
js
import { useValidateForm } from '@duxweb/dvha-core'
import * as yup from 'yup'
// 自定义异步验证函数
async function checkEmailExists(email) {
const response = await fetch(`/api/check-email?email=${email}`)
const data = await response.json()
return !data.exists
}
async function checkUsernameExists(username) {
const response = await fetch(`/api/check-username?username=${username}`)
const data = await response.json()
return !data.exists
}
const formData = ref({
email: '',
username: ''
})
const { validate } = useValidateForm({
data: formData,
rules: yup.object({
email: yup.string()
.email('请输入有效邮箱')
.required('邮箱是必填的')
.test('email-exists', '邮箱已被使用', checkEmailExists),
username: yup.string()
.required('用户名是必填的')
.min(3, '用户名至少3个字符')
.test('username-exists', '用户名已被使用', checkUsernameExists)
})
})
// 执行异步验证
async function handleAsyncValidate() {
try {
const result = await validate()
if (result.valid) {
console.log('异步验证通过')
}
else {
console.log('异步验证失败:', result.errors)
}
}
catch (error) {
console.error('验证过程出错:', error)
}
}复杂验证示例
js
import * as yup from 'yup'
const complexSchema = yup.object({
// 条件验证
hasJob: yup.boolean(),
company: yup.string().when('hasJob', {
is: true,
then: schema => schema.required('请填写公司名称'),
otherwise: schema => schema.notRequired()
}),
// 数组验证
tags: yup.array()
.of(yup.string().required())
.min(1, '至少选择一个标签')
.max(5, '最多选择5个标签'),
// 对象验证
address: yup.object({
province: yup.string().required('请选择省份'),
city: yup.string().required('请选择城市'),
detail: yup.string().required('请填写详细地址')
}),
// 日期验证
birthday: yup.date()
.required('请选择生日')
.max(new Date(), '生日不能是未来日期'),
// 文件验证
avatar: yup.mixed()
.test('fileSize', '文件大小不能超过2MB', (value) => {
return !value || value.size <= 2 * 1024 * 1024
})
.test('fileType', '只支持图片格式', (value) => {
return !value || ['image/jpeg', 'image/png', 'image/gif'].includes(value.type)
})
})对比两种验证方式
| 特性 | vee-validate 内置规则 | Yup Schema 验证 |
|---|---|---|
| 语法 | 字符串格式 | 对象链式调用 |
| 类型安全 | ❌ | ✅ |
| 异步验证 | ❌ | ✅ |
| 条件验证 | ❌ | ✅ |
| 复杂逻辑 | ❌ | ✅ |
| 学习成本 | 低 | 中等 |
| 性能 | 较好 | 良好 |
| 包大小 | 小 | 较大 |
| 自定义 | 有限 | 高度可定制 |
选择建议
- 简单表单:推荐使用 vee-validate 内置规则,语法简洁,开发快速
- 复杂表单:推荐使用 Yup Schema,功能强大,类型安全
- 异步验证:必须使用 Yup Schema
- 条件验证:推荐使用 Yup Schema
- TypeScript 项目:推荐使用 Yup Schema,有更好的类型支持
与组件集成示例
vue
<script setup lang="ts">
import { initFormValidate, useValidateForm } from '@duxweb/dvha-core'
import { computed, ref } from 'vue'
import * as yup from 'yup'
// 初始化内置规则
initFormValidate()
const formData = ref({
name: '',
email: '',
validationType: 'builtin' // 'builtin' | 'yup'
})
// 内置规则验证
const builtinRules = {
name: 'required|min:2',
email: 'required|email'
}
// Yup Schema 验证
const yupSchema = yup.object({
name: yup.string()
.required('姓名是必填的')
.min(2, '姓名至少2个字符'),
email: yup.string()
.required('邮箱是必填的')
.email('请输入有效邮箱')
})
// 根据选择动态切换验证方式
const currentRules = computed(() => {
return formData.value.validationType === 'builtin' ? builtinRules : yupSchema
})
const { validate, reset } = useValidateForm({
data: formData,
rules: currentRules
})
const errors = ref({})
const isValidating = ref(false)
async function handleValidate() {
isValidating.value = true
try {
const result = await validate()
errors.value = result.valid ? {} : result.errors
return result.valid
}
finally {
isValidating.value = false
}
}
async function handleSubmit() {
const isValid = await handleValidate()
if (isValid) {
console.log('表单提交:', formData.value)
}
}
function handleReset() {
formData.value = {
name: '',
email: '',
validationType: formData.value.validationType
}
errors.value = {}
reset()
}
</script>
<template>
<form @submit.prevent="handleSubmit">
<div>
<label>验证方式:</label>
<select v-model="formData.validationType">
<option value="builtin">
vee-validate 内置规则
</option>
<option value="yup">
Yup Schema 验证
</option>
</select>
</div>
<div>
<label>姓名:</label>
<input
v-model="formData.name"
type="text"
:class="{ error: errors.name }"
>
<span v-if="errors.name" class="error-text">{{ errors.name }}</span>
</div>
<div>
<label>邮箱:</label>
<input
v-model="formData.email"
type="email"
:class="{ error: errors.email }"
>
<span v-if="errors.email" class="error-text">{{ errors.email }}</span>
</div>
<div>
<button
type="submit"
:disabled="isValidating"
>
{{ isValidating ? '验证中...' : '提交' }}
</button>
<button type="button" @click="handleReset">
重置
</button>
</div>
</form>
</template>
<style>
.error {
border-color: red;
}
.error-text {
color: red;
font-size: 12px;
}
</style>