# form-fast-validator **Repository Path**: ntbl/form-fast-validator ## Basic Information - **Project Name**: form-fast-validator - **Description**: 一个快速创建表单验证的策略库 - **Primary Language**: JavaScript - **License**: Not specified - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 36 - **Forks**: 4 - **Created**: 2017-11-19 - **Last Updated**: 2022-07-11 ## Categories & Tags **Categories**: javascript-toolkits **Tags**: None ## README [TOC] # Form-fast-validator 一个快速创建表单验证的异步 (Promise) 策略库。 ## 特性 1. 组合异步验证(Promise) 2. 模块化 3. 高度可扩展 4. 快捷事件方法 5. 生命周期钩子 4. 内置了常用的策略验证和正则库 5. 压缩后大小约 `7kb` ## 简介 [![npm](https://img.shields.io/badge/npm-v2.0.0-blue.svg)](https://www.npmjs.com/package/form-fast-validator) [![GitHub](https://img.shields.io/badge/GitHub-yeshimei-green.svg)](https://github.com/yeshimei/form-fast-validator) [![码云](https://img.shields.io/badge/码云-Sunny-green.svg)](https://www.npmjs.com/package/form-fast-validator) [![IE8+](https://img.shields.io/badge/IE-8+-green.svg)](https://www.npmjs.com/package/form-fast-validator) [![MIT](https://img.shields.io/npm/l/express.svg)](https://www.npmjs.com/package/form-fast-validator) ` form-fast-validator` 一个快速创建表单验证的策略库。 它的核心实现了一个`高度可扩展`的`同/异步` `模块封装`机制 —— 验证策略,让您可以以组合的方式任意搭配自己的验证方案。在内部,为了保证性能消耗的最小代价,实现了一个类似管道的验证处理流程。 为了进一步加快创建您的验证方案,它还`内置`了常用的验证策略和正则表达式。 在异步方面,它基于 `Promise` 实现了组合异步验证,在不同字段和整个表单的范围内自动管理异步执行。 不同于其他验证库,它还对事件绑定进行了快捷使用和异步封装。 当然,它还有一些做不到事,但它仍然把整个世界送给你 —— `生命周期钩子` ## 安装 ``` npm install form-fast-validator --save ``` ## 引入 作为 `nodeJs 模块` 或者配合相关打包工具,比如 `webpack`: ```javascript var Validator = require('form-fast-validator') // bebel or es6 import Validator from 'form-fast-validator' ``` 通过 ` ``` ## 使用 ### 基本 基本的 `HTML` 表单结构。 ```html
``` 实例化 `Validator`,并将表单元素传入。 ```javascript var f = document.forms[0] var validator = new Validator(f) ``` 通过实例的 `.add()` 方法为每个字段注册验证策略。 ```javascript validator .add('username', [ ['notEmpty', '用户名不能为空'], ['minLength', 3, '至少3个字符'], ['maxLength', 10, '最多10个字符'], ]) // ... .add('email', [ ['notEmpty', '邮箱不能为空'], ['test', 'email', '格式不正确'] ]) // ... ``` 在事件回调中,通过实例的 `.result()` 方法启动并获取验证结果,`.getData()` 方法获取表单字段数据。 ```javascript // 单字段 f.oninput = function (e) { // 当 result 方法指定一个字段名时, 只验证指定的字段 // 当 result 方法未指定字段名时, 验证所有已注册的字段 validator.result(e.target.name) } // 全部字段 f.onsubmit = function (e) { e.preventDefault() if (validator.result()) { // getData 方法接受多个字段名,返回表单字段数据时,会忽略指定的字段 console.log(validator.getData()) } } ``` **现在,您可以到 [codepen.io](https://codepen.io/yeshimei/pen/GOyBRL) 查看这个简单的演示。** ### 快捷事件方法 使用实例的 `快捷事件方法` ,简化上述代码。 ```JavaScript validator // 自动为每个已注册的字段执行 result() 方法来启动验证 // 内部是为每个已注册字段绑定 input 事件 .oninput() // 为表单元素绑定 submit 事件并启动验证 // 当验证通过时,执行传入的回调函数 // 内部是为表单元素绑定 submit 事件(意味着,你表单里必须有个 type='submit' 的提交按钮) .onsubmit(function () { console.log(this.getData()) }) ``` ## 进阶 ### 自定义消息元素 通过实例的 `config.info`,可自定义消息元素的 class、类型和默认文本。 **注意:消息元素会在添加验证策略时生成并插入到对应字段的后面。** ```javascript validator.config.info = { className: '', // class type: 'span', // 元素类型 text: '' // 默认文本 } ``` 或者,你也可以传入一个函数,发挥 `JavaScript` 原生的威力。 ```javascript // 参数分别为当前字段元素和字段名 validator.config.info = function (el, name) { // 自定义消息元素 el.insertAdjacentHTML('afterend', '') // 最后,您需要返回它 // 必须是一个真实的 dom 元素 return el.nextElementSibling }) ``` ### 扩展正则库 `validator` 内置了一些常用的正则,可由 `__pattern` 属性访问,但通常不建议直接扩展,而是通过实例的 `.pattern()` 方法。因为,它提供了一个命名冲突的检查机制。 它接受三个参数: - **name:** 正则的名称。 - **pattern:** 正则表达式。 - **force=false:** 可选。如果添加的正则已存在,默认抛出异常。指定为 `true` 时,将会强制覆盖已存在的正则(包括内置)。 ```javascript validator .pattern('username', /^[0-9a-zA-Z_]+$/) .pattern('password', /^[0-9a-zA-Z]+$/) ``` 或者, 一次性批量添加。 ```javascript validator .pattern({ 'username': /^[0-9a-zA-z_]+$/, 'password': /^[0-9a-zA-Z]+$/ }) ``` 所有内置和已扩展的正则都可以作为实例的 `test 验证策略` 的参数使用。 ```javascript validator .add('username', [ // ... ['test' , 'username', '只能包含数字、字母和下划线'] // 注意,错误消息是必须存在的,哪怕是一个空字符串 // 您还会在下面,看到多次如上的提醒 ]) ``` 此外,您还可通过 `rawTest 验证策略` 快速使用一个正则。 ```javascript validator .add('username', [ // ... ['rawTest' , /^[0-9a-zA-z_]+$/, '只能包含数字、字母和下划线'] ]) ``` ### 扩展验证策略 验证策略和正则库类似。`validator` 也内置了一些常用的验证策略: - 普通验证策略 - 异步验证策略 #### 普通验证策略 普通验证策略是对同步验证方法的封装,可由 `__strategy` 属性访问,通过实例的 `.strategy()` 方法添加。 现在,让我们学习一个简单的例子,为我们的 `number`字段添加一个验证数值范围的策略: ```javascript validator // 首先, 添加一个数值范围验证的普通策略 .strategy('range', function(field, err, start, end) { // 获取到字段元素的值 // 也就是用户在表单字段里输入的值 var value = field.value if (value < start || value > end) { // 函数的返回值将作为页面上消息元素的显示内容 // 通常,我们只需要在验证不通过时返回 err 即可 // err 是我们在注册验证策略时自定义的错误消息 // 还记得,那个必须存在的错误消息吗? return err } }) ``` 以上,每个验证策略(包括异步验证策略)都接受一个 `field` 字段对象作为其第一个参数: - **name:** 字段名 - **el:** 字段的元素 - **value=' ':** 字段的值 - **pass=null:** 字段是否验证通过 - **infoEl:** 与字段对应的错误元素 - **infoMsg=' ':** 错误元素的内容 - **required=false:** 字段是否为必填 - **disabled=false:** 是否禁止字段验证 - **strategy=[]:** 已注册的普通验证策略 - **async=[]:** 已注册的异步验证策略 用户自定义的错误消息 `err` 作为其第二个参数。通常,我们应该在策略验证失败时,返回它。 紧接着,我们指定了两个自定义参数 `start, end`。 现在,让我们看看如何它: ```javascript // 为 number 字段注册 range 验证策略 .add('number', [ ['range', 10, 100, '数值的范围在 10 到 100'] ]) ``` 我们每一条验证策略都是一个数组,里面的元素分别是 - 需要使用的验证策略的名称 `range` - 传入验证策略的实参 `10, 100` - 用户自定的错误消息 `'数值的范围在 10 到 100'` **(注意,错误消息是必须存在的)** 是不是很简单!!! 当然,`strategy` 也支持批量添加。 ```javascript validator .strategy({ 'a': fn, 'b': fn, // .... }) ``` #### 异步验证策略 异步验证策略是对基于 Promise 异步验证方法的封装,可由 `__async` 属性访问,通过实例的 `async()` 方法添加。 现在,我们使用 `setTimeout` 计时器模拟一个异步获取用户名是否可用的简单例子: ```javascript validator // msg 异步成功时返回的成功消息 // err 异步失败时返回的错误消息 // is 自定义参数 .async('ajaxUsername', function (field, msg, err, is) { // 必须返回一个 promise 实例 return new Promise(function (resolve, reject) { field.infoMsg = '正在查询中...' setTimeout(function () { if (field.value === is) { // 异步成功了! // 把我们的成功消息返回 resolve(msg) } else { // 异步失败了! // 那就把错误消息返回吧! reject(err) } }, 2000) }) }) ``` ```javascript .add('username', [ ['notEmpty', '不能为空'], ['minLength', 3, '至少3个字符'], ['maxLength', 10, '最多10个字符'], // 注册异步验证策略 // 和同步不同,成功消息和错误消息都必须存在 // 还是那句话,哪怕是一个空字符串 ['ajaxUsername', 'sunny' '用户名可用', '用户名不可用'] ]) ``` 当 `username` 字段一旦注册了 `异步验证策略`, 实例的 `result` 方法就会发生改变。它将返回一个 `promise 实例`, 而不是一个 `布尔值`(在一个字段只有普通验证策略时它返回一个布尔值指代此字段是否通过了验证)。 ```javascript f.username.oninput = function (e) { // 返回了一个 Promise 实例 validator.result('username') .then(function() { console.log(e.target.value) }, function () { console.log('失败!!!') }) } // 如果您只关心异步的成功状态,就可以使用快捷事件方法简化上面的代码。 // 它们会自动切换 result 对 同步和异步的处理 validator .oninput(function (e) { console.log(e.target.value) }) ``` 最后,让我们深入一下验证策略的内部原理: ![](http://os7bzfev4.bkt.clouddn.com/17-11-24/15521421.jpg) `username` 字段在遍历执行验证策略时,会优先 `由上至下 `执行所有的普通验证策略,一旦验证失败就会终止遍历。直到所有的普通验证策略验证成功后,才会由 `Promise.all()` 方法一并执行异步验证策略,这意味着,如果其中一个异步验证失败就会导致所有验证失败。 **注意:如果 result() 方法未指定字段名, 将会把整个表单的验证策略当做一个整体。** ### 生命周期钩子 在它的世界里,你可通过实例的 `hook()` 方法,注目它的一生。 - **registered(field):** 字段注册成功后调用(此时,所有验证策略已载入,字段对象已生成) - **fieldSucceed(field):** 字段验证通过后调用 - **fieldFailed(field):** 字段验证失败后调用 - **succeed(container):** 所有已注册的字段通过后调用 - **failed(container):** 所有已注册的字段失败后调用 - **error(err):** 抛出错误时调用 ```javascript validator .hook('fieldSucceed', function (field) { console.log(field.name + '通过') }) .hook('fieldFailed', function (field) { console.log(field.name + '失败') }) // 或者, 传入一个对象 validator .hook({ fieldSucceed: fn, fieldFailed: fn, succeed: fn // ... }) ``` **注意: 后面重复声明的钩子会覆盖掉前面已存在的钩子** ### 字段对象 我们在 `扩展异步验证策略` 已经初识了 `字段对象`, 它有以下属性: - **name:** 字段名 - **el:** 字段的元素 - **value='':** 字段的值 - **pass=false:** 字段是否验证通过 - **infoEl:** 与字段对应的错误元素 - **infoMsg='':** 错误元素的内容 - **required=false:** 字段是否为必填 - **disabled=false:** 是否禁止字段验证 - **strategy=[]:** 已注册的普通验证策略 - **async=[]:** 已注册的异步验证策略 **注意: `value` 和 `infoMsg` 会实时反应您的改动。 而其他属性则会在验证启动时生效。** 您有两种方法可以改动字段对象 - `strategy` 、`async` 方法和 一些 `生命周期钩子` 都会把当前字段的字段对象作为参数传递,你可以直接进行修改 - 如果你要在其他无法获得字段对象的地方修改,需要通过以下方法: - **set(name, key, value)** - **setInfo(name, value)** - **setValue(name, value)** - **setPass(name, value)** ### 异常捕获 默认情况下,内部异常会直接抛出。您可指定实例的 `config.debug ` 为 `false` 禁止内部抛出异常。 一般,我们只会在产品发布时,这样做。 更好的做法是,指定 `error` 钩子。 ``` validator.hook('error', function (err) { if (err) { // ... } }) ``` 它将捕获所有内部异常。 **注意: `error` 钩子必须在实例最前面指定,因为部分的内部异常会在初始化时抛出** ## 代码风格 ### 结构 `Validator` 内置的多数方法都支持链式调用,所以,您可以如下组织您的代码结构: ```javascript var validator = new Validator() validator .hook() // 生命周期钩子 .pattern() // 添加正则 .strategy() // 添加普通验证策略 .async() // 添加异步验证策略 .add() // 注册字段 // ... .oninput // 快捷事件方法 // ... ``` ### 模块化 当您管理的表单过多时,把所有正则和验证策略的添加都放在实例上,始终不是个好办法,还可能因为原型共享而发生命名冲突的问题。 既然,我们使用了原型,为何不乘上它的便车呢? 在一个模块中集中管理我们的正则和验证策略: ```javascript // pattern.js new patternExtend = Validator() patternExtend .pattern() // ... ``` ```javascript // strategy.js new strategyExtend = Validator() strategyExtend .strategy() .async() // ... ``` 现在,您就可以在任何实例中使用它们了。 如果,实例有唯一的添加时,您可以通过 `命名空间` 管理它们: ``` v1 pattern('v1-username') v2 pattern('v2-username) ``` ## API ### Validator 构造器 new Validator(form [Element], options O/F) ### validator 实例化对象 #### 配置 - **config.error.className=' ':** 错误元素的 class - **config.error.type='span':** 错误元素的类型 - **config.error.text=' ':** 错误元素的默认文本 - **config.debug=true:** 是否开启调试 #### 核心方法 - **add(name S, validator A):** 为字段添加验证策略 - **pattern(name S, pattern [regexg], force=false? B):** 添加一个正则表达式 - **pattern(obj {name: regexg}, force=false? B):** 添加多个正则表达式 - **strategy(name S, pattern [regexg], force=false? B):** 添加一个普通验证策略 - **strategy(obj {name: regexg}, force=false? B):** 添加多个普通验证策略 - **async(name S, pattern [regexg], force=false? B):** 添加一个异步验证策略 - **async(obj {name: regexg}, force=false? B):** 添加多个异步验证策略 - **hook(name S, pattern [regexg]):** 添加一个生命周期钩子 - **hook(obj {name: regexg}):** 添加多个生命周期钩子 - **result(name=undefined? S):** 启动并获取验证结果 - **getData(ignoreName1=undefined? S, ...):** 获取表单字段数据 #### 字段对象 - **set(name S, key S, value [any]):** 设置 name 字段的字段对象指定属性的值 - **setInfo(name S, value [any]):** 设置错误内容 `infoMsg` 的快捷方法 - **setValue(name S, value [any]):** 设置字段值 `value` 的快捷方法 - **setPass(name S, value [any]):** 设置字段验证是否通过 `pass` 的快捷方法 #### 事件方法 通过快捷事件方法监听的字段不能注册任何异步验证策略。 - **oninput(fn F):** 为所有已注册字段绑定 `input` 事件 - **onsubmit(fn F):** 为表单绑定 `submit` 事件 #### 策略方法 策略方法并不能直接使用,而是在注册验证策略时由字符串的形式指定。而验证策略的自定参数必须紧跟其后,自定义错误消息作为最后一个元素,且**必须存在**。 **注意, 异步验证策略必须存在两个消息 —— 成功和失败** ```javascript validator .add('username', [ // minLength 需要使用的策略方法 // 3 自定义参数 ['minLength', 3, '至少3个字符'] ]) ``` #### 普通策略方法 - **notEmpty():** 字段不能为空(必填) - **minLength(length):** 最小字段长度 - **maxLength(length):** 最大字段长度 - **min(length):** 最小值 - **max(length):** 最大值 - **equal(name):** 是否匹配某个字段值 - **test(insideRegexpName, ...):** 正则验证。此方法只接受内置或已扩展的正则名 - **rawTest(regexp):** 正则验证,接受一个正则表达式 - **disabled():** 禁止字段验证 #### 异步策略方法 暂无 #### 内置正则库 - **email:** 邮箱 - **phone:** 国内手机号 - **id:** 18 位身份证号 - **qq:** QQ号 - **weChat:** 微信号 - **zipCode:** 邮政编码 ## Notes 暂无 ## License [MIT](License)