Skip to content

useValidator

表单验证器

使用方法

首先,需要安装 async-validator 包:

bash
npm install async-validator --save-dev

然后,本地创建 useValidator.ts 文件并写入如下代码:

ts
import Schema, { type Rules, ValidateError, Values, type Rule, ValidateFieldsError } from 'async-validator';

export const useValidator = (
    rules: Rules,
    data: Record<string, any>
): Promise<{ errors: ValidateError[] | null, fields: ValidateFieldsError | Values }> => {
    return new Promise((resolve) => {
        const validator = new Schema(rules);
        validator.validate(data, (errors, fields) => {
            resolve({ errors, fields });
        });
    })
}

export { Rules, Rule }

使用示例

ts
// 校验规则
const generateRules = (): Rules => {
    return {
        name: { required: true, message: '请输入名称', transform(value) {return value.trim()} },
        age: [{ required: true, message: '请输入年龄' }, { type: 'number', message: '请输入数字'}],
        sex: { required: true, type: 'enum', enum: ['男', '女'] }
    }
}

// 保存时校验表单
const { errors, fields } = await useValidator(generateRules(), formData.value);
if (errors) {
    return ElMessage.error(errors[0].message);
}

参数

参数说明类型默认值
rules校验规则Rules-
data待校验的数据Record<string, any>-

返回值

参数说明类型
errors返回错误结果ValidateError[] | null
fields1. 没有错误时返回处理后的表单数据
2. 有错误时返回错误字段和错误结果
ValidateFieldsError | Values

支持校验类型

  • string: Must be of type stringThis is the default type.
  • number: Must be of type number.
  • boolean: Must be of type boolean.
  • method: Must be of type function.
  • regexp: Must be an instance of RegExp or a string that does not generate an exception when creating a new RegExp.
  • integer: Must be of type number and an integer.
  • float: Must be of type number and a floating point number.
  • array: Must be an array as determined by Array.isArray.
  • object: Must be of type object and not Array.isArray.
  • enum: Value must exist in the enum.
  • date: Value must be valid as determined by Date
  • url: Must be of type url.
  • hex: Must be of type hex.
  • email: Must be of type email.
  • any: Can be any type.

完整规则示例

ts
import Schema from 'async-validator';

// 定义校验规则
const rules = {
	// 1. 字符串类型校验(用户名)
	username: [
		{
			type: 'string', // 类型必须为字符串
			required: true, // 必填项
			message: '用户名不能为空', // 错误提示
		},
		{
			min: 3, // 最小长度 3
			max: 10, // 最大长度 10
			message: '用户名长度必须在 3-10 个字符之间',
		},
		{
			pattern: /^[a-zA-Z0-9_]+$/, // 只能包含字母、数字、下划线
			message: '用户名只能包含字母、数字和下划线',
		},
	],

	// 2. 数字类型校验(年龄)
	age: [
		{
			type: 'number', // 类型必须为数字(注意:字符串数字会被视为无效)
			required: true,
			message: '年龄不能为空',
		},
		{
			min: 0, // 最小值 0
			max: 120, // 最大值 120
			message: '年龄必须在 0-120 之间',
		},
		{
			validator(rule, value) {
				// 自定义校验:必须为整数
				if (!Number.isInteger(value)) {
					return Promise.reject('年龄必须为整数');
				}
				return Promise.resolve();
			},
		},
	],

	// 3. 布尔值校验(是否同意协议)
	agree: [
		{
			type: 'boolean',
			required: true,
			message: '请同意用户协议',
		},
		{
			validator(rule, value) {
				// 必须为 true(勾选状态)
				if (value !== true) {
					return Promise.reject('必须同意用户协议才能继续');
				}
				return Promise.resolve();
			},
		},
	],

	// 4. 数组校验(爱好列表)
	hobbies: [
		{
			type: 'array',
			required: true,
			message: '至少选择一个爱好',
		},
		{
			min: 1, // 至少选择 1 项
			max: 3, // 最多选择 3 项
			message: '爱好选择数量必须在 1-3 之间',
		},
		{
			validator(rule, value) {
				// 自定义校验:必须包含指定选项(如 'reading')
				if (!value.includes('reading')) {
					return Promise.reject('爱好必须包含阅读');
				}
				return Promise.resolve();
			},
		},
	],

	// 5. 对象校验(地址信息)
	address: [
		{
			type: 'object',
			required: true,
			message: '地址信息不能为空',
		},
		{
			// 嵌套对象校验
			fields: {
				city: [
					{ type: 'string', required: true, message: '城市不能为空' },
				],
				street: [
					{ type: 'string', required: true, message: '街道不能为空' },
					{ min: 5, message: '街道名称至少 5 个字符' },
				],
				zipCode: [
					{ type: 'string', required: true, message: '邮编不能为空' },
					{ pattern: /^\d{6}$/, message: '邮编必须是 6 位数字' },
				],
			},
		},
	],

	// 6. 邮箱格式校验
	email: [
		{
			type: 'email', // 内置邮箱格式校验
			required: true,
			message: '请输入有效的邮箱地址',
		},
	],

	// 7. 自定义异步校验(模拟后端校验用户名是否已存在)
	nickname: [
		{
			type: 'string',
			required: true,
			message: '昵称不能为空',
		},
		{
			async validator(rule, value) {
				// 模拟异步请求(如调用后端接口)
				return new Promise((resolve, reject) => {
					setTimeout(() => {
						const existNicknames = ['admin', 'root', 'guest'];
						if (existNicknames.includes(value)) {
							reject('该昵称已被占用,请更换');
						} else {
							resolve();
						}
					}, 500); // 模拟网络延迟
				});
			},
		},
	],

	// 8. 枚举值校验(性别)
	gender: [
		{
			type: 'enum',
			enum: ['male', 'female', 'other'], // 只能是指定值
			required: true,
			message: '请选择性别',
		},
	],

	// 9. 日期格式校验
	birthday: [
		{
			type: 'date', // 支持 Date 对象或 ISO 格式字符串(如 '2020-01-01')
			required: true,
			message: '请输入有效的出生日期',
		},
		{
			validator(rule, value) {
				// 出生日期不能晚于当前时间
				const now = new Date();
				if (new Date(value) > now) {
					return Promise.reject('出生日期不能晚于当前时间');
				}
				return Promise.resolve();
			},
		},
	],
};