如何设计一个高级通用的表单校验函数
表单校验在 Web 开发中是必不可少的一环。在用户提交表单之前进行有效性验证能够确保输入的数据合法有效。为了提高开发效率、减少重复工作以及提高项目的可维护性和可扩展性,设计一个高级通用的表单校验函数就显得尤为重要。
设计思路
设计高级通用的表单校验函数需要考虑以下几点:
- 收集表单数据:针对前端页面中的表单元素获取用户输入的数据。这个数据可能包括文本、数字、日期、时间等。一般建议采用类似 "id-value" 的格式进行获取,以减少页面元素的依赖。
- 定义校验规则:需要明确每个表单元素必须满足哪些要求。比如是否必填、长度限制、格式验证等。定义表单规则时,建议采用对象存储规则,其中每个表单元素对应一个验证器数组,每个验证器又包括一个验证函数和相应的错误提示信息。采用这种方式,你就可以轻松添加新的验证器,而不需要修改验证函数本身。
- 实现校验逻辑:在规则的基础上对表单数据进行逐一检查,判断数据是否符合规则。校验顺序是按照添加的顺序进行校验,前一个校验器出现错误,则不再进行后续校验,这样可以避免重复校验,同时还可以提高性能。
- 展示错误信息:在校验数据之后,需要把错误信息展示给用户。你可以选择把所有的错误信息进行一次性展示,也可以对每个表单元素单独进行提示。同时,对于提交的数据,你需要进行数据清洗处理,避免无效数据被提交。
代码实现
下面是一个高级通用表单校验函数的示例代码:
/**
* 对单个表单项的值进行校验
* @param {String} value 表单项的值
* @param {Array} rules 表单校验规则数组,每个元素是一个包含 validator 和 message 两个属性的对象
* @returns {String} 如果校验通过,返回 "",否则返回错误提示信息
*/
function validateItem(value, rules) {
for (let i = 0; i < rules.length; i++) {
const rule = rules[i];
if (!rule.validator(value)) {
return rule.message;
}
}
return "";
}
/**
* 对整个表单进行校验
* @param {Object} formData 表单数据对象
* @param {Object} ruleList 表单校验规则对象
* @returns {Object} 返回一个包含错误信息的对象,如果所有校验规则都通过,则返回一个空对象
*/
function validateForm(formData, ruleList) {
const errors = {};
for (const itemName in ruleList) {
if (ruleList.hasOwnProperty(itemName)) {
const rules = ruleList[itemName];
const value = formData[itemName];
const errMsg = validateItem(value, rules);
if (errMsg) {
errors[itemName] = errMsg;
}
}
}
return errors;
}
/**
* 表单提交事件处理函数
* @param {Event} e
*/
function handleSubmit(e) {
e.preventDefault();
// 获取表单数据
const formData = {};
for (const el of e.target.elements) {
if (el.name) {
formData[el.name] = el.value.trim();
}
}
// 定义校验规则
const ruleList = {
"username": [
{ validator: (v) => !!v, message: "用户名不能为空" },
{ validator: (v) => /^[a-zA-Z0-9_]{4,16}$/.test(v) , message: "用户名必须是4-16位的字母、数字或下划线" },
],
"password": [
{ validator: (v) => !!v, message: "密码不能为空" },
{ validator: (v) => /^[\w@!#^$?%^&*()+=|{}[\]:;'",.<>\/?\\~`-]{6,16}$/.test(v), message: "密码必须是6-16位且包含数字、字母和特殊字符" },
],
"repassword": [
{ validator: (v) => !!v, message: "确认密码不能为空" },
{ validator: (v, formData) => v === formData.password, message: "两次密码输入不一致" },
],
"email": [
{ validator: (v) => /^\w+@[a-z0-9]+\.[a-z]+$/i.test(v), message: "邮箱格式不正确" },
],
};
// 校验表单数据
const errors = validateForm(formData, ruleList);
if (Object.keys(errors).length) {
// 显示错误信息
// ...
console.log(errors);
return;
}
// 处理表单数据
// ...
}
在上述代码中,我们将表单数据和校验规则都抽象为对象,相比数组形式的规则定义,对象形式更加直观易懂。其中,校验规则对象的每个属性名对应表单项的 name 属性,属性值是一个规则数组,每个数组元素是一个对象,包含 validator 和 message 两个属性,分别表示校验函数和错误提示信息。表单数据对象的属性名同样对应表单项的 name 属性,属性值是表单项的值。
在校验逻辑中,我们遍历校验规则对象,逐一获取规则数组,针对每个表单项的值,调用 validateItem 函数,如果校验未通过,则将错误信息存入一个对象,最终将错误信息对象返回。
在编写校验函数时,需要注意以下几点:
- 校验函数的返回值必须是布尔类型,符合规则返回 true,否则返回 false。
- 部分校验函数需要使用到 formData 传递的其他表单项的值,比如表单项 A 的校验规则依赖于表单项 B 的值,则可以定义函数参数为 (value, formData)。
- 在表单项数量较多时,编写规则对象和表单数据对象可能比较麻烦,此时可以借助一些表单校验库,比如 VeeValidate、Validator.js 等,它们提供了一些方便的方法来定义表单校验规则,可以大大减少开发难度。
总结
设计高级通用的表单校验函数需要考虑校验规则、校验逻辑、错误信息提示和数据清洗等因素,同时需要使用一些优秀的编程习惯和技巧,比如定义校验函数和规则对象,将表单数据和校验规则分离等。在编写校验函数时需要严格按照要求返回布尔类型,并且注意参数传递的顺序,方便于适配各种校验需求。
本作品采用 知识共享署名-相同方式共享 4.0 国际许可协议 进行许可。