首页 最新 热门 推荐

  • 首页
  • 最新
  • 热门
  • 推荐

  • 24-11-26 09:05
  • 3790
  • 16564
juejin.cn

在前端开发中,表单验证是一个常见且重要的需求。传统的表单验证往往导致代码重复、管理困难,尤其在面对复杂的表单时,验证逻辑容易变得混乱。为了提高开发效率和保证数据准确性,我们开发了一个高度自定义的表单验证器,能够应对各种复杂的验证场景,并支持灵活扩展新的验证规则。

一、目标与背景

表单验证是前端开发中常见的需求。很多时候,我们需要验证用户输入的数据是否符合特定规则,例如检查是否为空、是否为合法邮箱、是否符合手机号的格式等。然而,传统的表单验证往往会导致代码重复、管理困难,尤其在面对复杂的表单时,验证逻辑容易变得凌乱。

为了解决这些问题,开发一个通用的表单验证器,它具有以下特点:

  • 简洁易用:只需简单的配置即可进行表单验证。
  • 高度扩展:提供了多种常见的验证规则,并支持自定义规则。
  • 可视化反馈:能够通过添加 CSS 类自动标记出验证失败的表单项,提升用户体验。
  • 灵活处理:支持在验证时进行自定义校验逻辑,满足不同场景的需求。

二、结构和功能

1、构造函数与验证规则

表单验证器的构造函数如下:

javascript
代码解读
复制代码
function FormValidator(formId) { this.formId = formId; this.validationRules = { required: function (value) { /* 规则 */ }, email: function (value) { /* 规则 */ }, phone: function (value) { /* 规则 */ }, landline: function (value) { /* 规则 */ }, idCard: this.validateIDCard, number: function (value) { /* 规则 */ }, minLength: function (value, length) { /* 规则 */ }, maxLength: function (value, length) { /* 规则 */ }, pattern: function (value, regex) { /* 规则 */ }, custom: function (value, validator) { /* 规则 */ }, }; this.addEventListeners(); }

在此构造函数中,我们为常见的验证规则(如required、email、phone等)定义了相应的验证函数,便于后续调用和扩展。

2、身份证号校验方法

身份证号验证是一个常见的需求,为了确保身份证号码的有效性,我们实现了如下校验逻辑:

javascript
代码解读
复制代码
FormValidator.prototype.validateIDCard = function (idCard) { if (idCard.length !== 18) return '不是有效的身份证号码!'; if (!/^[0-9Xx]+$/.test(idCard)) return '身份证号码包含无效字符!'; const factors = [7, 9, 10, 5, 8, 4, 2, 1, 6, 3, 7, 9, 10, 5, 8, 4, 2]; const checksums = ['1', '0', 'X', '9', '8', '7', '6', '5', '4', '3', '2']; let sum = 0; for (let i = 0; i < 17; i++) { sum += parseInt(idCard[i], 10) * factors[i]; } return checksums[sum % 11] === idCard[17].toUpperCase() ? undefined : '身份证号码校验码不正确!'; };

此方法结合长度、字符、和校验码三个层次进行验证,确保身份证号的准确性。

3、验证每个表单项

我们通过validateField方法验证每个表单项,并根据字段类型调用相应的规则进行校验:

javascript
代码解读
复制代码
FormValidator.prototype.validateField = function (field) { const { name, type, value, minLength, maxLength, pattern, errorMsg, customValidator } = field; let error; switch (type) { case 'required': error = this.validationRules.required(value); break; case 'email': error = this.validationRules.email(value); break; case 'phone': error = this.validationRules.phone(value); break; case 'landline': error = this.validationRules.landline(value); break; case 'idCard': error = this.validationRules.idCard.call(this, value); break; case 'number': error = this.validationRules.number(value); break; case 'text': if (minLength) error = this.validationRules.minLength(value, minLength); if (!error && maxLength) error = this.validationRules.maxLength(value, maxLength); break; case 'pattern': if (pattern) error = this.validationRules.pattern(value, pattern); break; case 'custom': if (customValidator) error = this.validationRules.custom(value, customValidator); break; } return error ? { name, type, value, errorMsg: errorMsg || error } : undefined; };

4、校验整个表单

validateForm方法负责验证整个表单,它会遍历表单数据并调用validateField进行逐项验证:

javascript
代码解读
复制代码
FormValidator.prototype.validateForm = function (formData = [], valiRules = [], callback) { const errors = []; const fields = this.processFormData(formData, valiRules); fields.forEach(field => { const error = this.validateField(field); if (error) { document.querySelector(`#${this.formId} [name="${error.name}"]`)?.classList.add('form-item-error'); errors.push(error); } }); if (callback && errors.length) callback(errors); return errors; };

5、处理表单数据

processFormData方法将表单数据与验证规则结合,为每个字段应用相应的规则:

javascript
代码解读
复制代码
FormValidator.prototype.processFormData = function (formData, valiRules) { return formData.map(item => { const rule = valiRules.find(attr => attr.name === item.name); return rule ? { ...item, ...rule } : item; }); };

6、添加事件监听器

为了提升用户体验,表单验证器还为每个输入字段添加了focus事件监听器,用于移除错误样式:

javascript
代码解读
复制代码
FormValidator.prototype.addEventListeners = function () { const formElement = document.querySelector(`#${this.formId}`); formElement?.querySelectorAll('input, textarea, select').forEach(input => { input.addEventListener('focus', e => e.target.classList.remove('form-item-error')); }); };

7、完整的代码

javascript
代码解读
复制代码
// 表单验证构造函数 function FormValidator(formId) { this.formId = formId; // 在构造函数中初始化实例变量 this.validationRules = { required: function (value) { return value ? undefined : '此字段为必填项'; }, email: function (value) { return /^[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,}$/i.test(value) ? undefined : '请输入有效的邮箱地址'; }, phone: function (value) { return /^1[3-9]\d{9}$/.test(value) ? undefined : '请输入有效的手机号码'; }, landline: function (value) { return /^(\d{3,4}-)?\d{7,8}$/.test(value) ? undefined : '请输入有效的座机号码'; }, idCard: this.validateIDCard, // 直接指向实例方法 number: function (value) { return /^\d+$/.test(value) ? undefined : '请输入有效的数字'; }, minLength: function (value, length) { return value.length >= length ? undefined : `长度至少为${length}个字符`; }, maxLength: function (value, length) { return value.length <= length ? undefined : `长度不得超过${length}个字符`; }, pattern: function (value, regex) { return regex.test(value) ? undefined : '格式不正确'; }, custom: function (value, validator) { return validator(value) ? undefined : '自定义验证未通过'; }, }; // 在构造函数中绑定事件监听器 this.addEventListeners(); } // 身份证号校验方法 FormValidator.prototype.validateIDCard = function (idCard) { if (idCard.length !== 18) { return '不是有效的身份证号码!'; } const validIdCardChars = /^[0-9Xx]+$/; if (!validIdCardChars.test(idCard)) { return '身份证号码包含无效字符!'; } const factors = [7, 9, 10, 5, 8, 4, 2, 1, 6, 3, 7, 9, 10, 5, 8, 4, 2]; const checksums = ['1', '0', 'X', '9', '8', '7', '6', '5', '4', '3', '2']; let sum = 0; for (let i = 0; i < 17; i++) { sum += parseInt(idCard[i], 10) * factors[i]; } const checkDigit = checksums[sum % 11]; if (checkDigit !== idCard[17].toUpperCase()) { return '身份证号码校验码不正确!'; } return undefined; }; // 校验单个字段方法 FormValidator.prototype.validateField = function (field) { let error = null; const { name, type, value, minLength, maxLength, pattern, errorMsg, customValidator } = field; // 根据字段类型进行校验 switch (type) { case 'required': error = this.validationRules.required(value); break; case 'email': error = this.validationRules.email(value); break; case 'phone': error = this.validationRules.phone(value); break; case 'landline': error = this.validationRules.landline(value); break; case 'idCard': error = this.validationRules.idCard.call(this, value); // 显式使用实例方法 break; case 'number': error = this.validationRules.number(value); break; case 'text': // 针对 text 类型,处理 minLength 和 maxLength 校验 if (minLength) error = this.validationRules.minLength(value, minLength); if (!error && maxLength) error = this.validationRules.maxLength(value, maxLength); break; case 'pattern': if (pattern) error = this.validationRules.pattern(value, pattern); break; case 'custom': if (customValidator) error = this.validationRules.custom(value, customValidator); break; default: break; } // 如果校验不通过,返回 errorMsg(如果提供),否则返回默认错误信息 const errorMessage = error ? errorMsg || error : undefined; // 返回带有字段信息的错误对象 return errorMessage ? { name, type, value, errorMsg: errorMessage } : undefined; }; // 校验整个表单方法 FormValidator.prototype.validateForm = function (formData = [], valiRules = [], callback) { let errors = [], fields = this.processFormData(formData, valiRules); fields.forEach(field => { const error = this.validateField(field); if (error) { // 添加class let inputElement = document.querySelector(`#${this.formId} [name="${error.name}"]`); if (inputElement) { inputElement.classList.add('form-item-error'); } // 收集所有错误 errors.push(error); } }); if (typeof callback === 'function' && errors.length > 0) { callback(errors); } return errors; // 返回包含错误信息的数组 }; // 表单数据处理 FormValidator.prototype.processFormData = function (formData, valiRules) { // 为 formData 中对应的项添加 valiRules 中的属性 const resultFormData = formData.map(item => { const attr = valiRules.find(attrItem => attrItem.name === item.name); if (attr) { return { ...item, ...attr }; } return item; }); return resultFormData; }; // 为表单项添加事件监听器 FormValidator.prototype.addEventListeners = function () { const formElement = document.querySelector(`#${this.formId}`); // 为每个输入字段添加事件监听 if (formElement) { const inputElements = formElement.querySelectorAll('input, textarea, select'); inputElements.forEach(input => { input.addEventListener('focus', e => { e.target.classList.remove('form-item-error'); // 去掉错误样式 }); }); } };

8、如何使用

使用表单验证器非常简单,只需传入表单 ID,并为每个表单字段配置验证规则。以下是一个简单的使用示例:

javascript
代码解读
复制代码
const validator = new FormValidator('myForm'); const formData = [ { name: 'username', value: 'mslion' }, { name: 'phone', value: '12345678901' }, { name: 'email', value: '[email protected]' }, { name: 'text', value: 'mslion' }, { name: 'landline', value: '08565642157' }, { name: 'idCard', value: '' }, { name: 'number', value: '45621' }, { name: 'pattern', value: 'abc123'}, { name: 'customField', value: 'CustomTest' }, ]; const valiRules = [ { name: 'username', type: 'required', errorMsg: '请选填写您的姓名' }, { name: 'phone', type: 'phone', errorMsg: '请输入电话' }, { name: 'email', type: 'email', errorMsg: '请输入邮箱' }, { name: 'text', type: 'text', minLength: 5, maxLength: 10, errorMsg: '文本不符合要求' }, { name: 'landline', type: 'landline', errorMsg: '请输入座机号' }, { name: 'idCard', type: 'idCard', errorMsg: '请输入身份证号' }, { name: 'number', type: 'number', errorMsg: '请输入数字' }, { name: 'pattern', type: 'pattern', pattern: /^[a-z0-9]+$/, errorMsg: '格式不正确' }, { name: 'customField', type: 'custom', customValidator: value => value.includes('Test'), errorMsg: '自定义验证未通过' }, ]; const errors = validator.validateForm(formData, valiRules, (errors) => { console.log(errors); });

可添加校验不通过的 class:

css
代码解读
复制代码
.form-item-error { color: #bb0000 !important; border-color: #bb0000 !important; } .form-item-error::placeholder { color: #bb0000 !important; }

三、总结

这个表单验证器设计灵活、易于扩展,能够处理常见的验证需求,并支持自定义规则。通过集成错误反馈机制,提升了用户体验。此外,它还为表单字段提供了清晰的验证逻辑,使得开发者可以轻松维护和扩展验证规则。无论你是前端开发新手,还是资深开发者,都能通过这个工具提高开发效率和代码质量。

原文地址

注:本文转载自juejin.cn的码手Lion的文章"https://juejin.cn/post/7440661589513093129"。版权归原作者所有,此博客不拥有其著作权,亦不承担相应法律责任。如有侵权,请联系我们删除。
复制链接
复制链接
相关推荐
发表评论
登录后才能发表评论和回复 注册

/ 登录

评论记录:

未查询到任何数据!
回复评论:

分类栏目

后端 (14832) 前端 (14280) 移动开发 (3760) 编程语言 (3851) Java (3904) Python (3298) 人工智能 (10119) AIGC (2810) 大数据 (3499) 数据库 (3945) 数据结构与算法 (3757) 音视频 (2669) 云原生 (3145) 云平台 (2965) 前沿技术 (2993) 开源 (2160) 小程序 (2860) 运维 (2533) 服务器 (2698) 操作系统 (2325) 硬件开发 (2492) 嵌入式 (2955) 微软技术 (2769) 软件工程 (2056) 测试 (2865) 网络空间安全 (2948) 网络与通信 (2797) 用户体验设计 (2592) 学习和成长 (2593) 搜索 (2744) 开发工具 (7108) 游戏 (2829) HarmonyOS (2935) 区块链 (2782) 数学 (3112) 3C硬件 (2759) 资讯 (2909) Android (4709) iOS (1850) 代码人生 (3043) 阅读 (2841)

热门文章

104
前端
关于我们 隐私政策 免责声明 联系我们
Copyright © 2020-2025 蚁人论坛 (iYenn.com) All Rights Reserved.
Scroll to Top