实现一个前端表单验证插件

3,113 阅读2分钟
原文链接: zhuanlan.zhihu.com

前言

2017 百度前端学院开课啦!里面有许多课题非常有意思,其中表单验证应该是前端同学接触最多的一个工作之一了。

表单验证不难,但是涉及到复杂交互,所以实现起来会比较繁琐。因此本文将会使用 es6、不依赖任何第三方库 实现一个简单的表单验证插件。

效果

<div class="form_group tel">
  <label for="name">手机</label>
  <input type="tel" name="tel" id="tel">
  <p class="message"></p>
</div>
// 配置
{
  target: '#tel', // 验证目标
  message: { target: '.tel p', success: '手机格式正确' }, // 验证信息显示的地方
  validators: [ // 验证规则数组
    { name: 'tel', args: { message: '手机格式错误' } }
  ]
}

效果 需翻墙

结构

我们的验证插件分为 `验证类Validator`,和 `验证规则validators`

`验证类Validator`: 为主逻辑,负责接受表单的配置并对表单执行相应的验证规则。

`验证规则validators`: 其内封装了大量的验证规则,供表单选用。

每个验证规则有着相同的结构,它们接收 表单的 value 返回验证结果和报错信息。例子如下:
// 针对手机号的验证规则
const tel = (str='', {message=''}={}) =>
({
  status: /^1[3|4|5|7|8][0-9]{9}$/.test(str), // 验证状态
  message // 报错信息
})

验证类Validator

结构
class Validator {
  // 接受配置 validatorConfig: 验证器配置, targetConfig: 针对于表单的配置
  /*
  * validatorConfig {}
  *   - error   每个表单验证失败时的函数   Function
  *   - success 每个表单验证成功时的函数   Function
  *   - reset   对表单执行重置操作时的函数 Function
  * targetConfig [{}, {}, ...] -> 各个表单的配置
  *   - target        验证目标的选择器  String(Selector)
  *   - message       验证信息的配置  Object
  *     - target      验证信息显示位置的选择器  String(Selector)
  * 	- placeholder 验证信息的默认值,重置时会显示该文本 String
  * 	- success     验证成功时会显示该文本   String
  * 	- validators    验证规则的配置  [{}, {}, ...] -> 各个验证规则的配置
  * 	  - name        验证规则的名字 (validators[key])  String
  * 	  - args        验证规则的配置参数  Object
  * 	    - message   必有 该规则验证失败的显示文本  String
  * 	    - ...   	该验证规则的其他配置参数  Any (各验证规则不同)
  */
  constructor (config) {}
  // 验证主逻辑
  _check () {}
  // 单个表单的验证 (只对单个表单执行 _check)
  run () {}
  // 执行全部表单的验证 (对所有要验证的表单执行 _check)
  runAll () {}
  // 重置表单为初始状态
  reset () {}
}
验证主逻辑 _check
其接受 验证表单的配置,并执行相应验证逻辑
如接受了以下配置:
{
  target:  '#tel', // 验证目标
  // 验证信息显示的地方
  message:  { target: '.tel p', success: '手机格式正确' }, 
  validators: [ // 验证规则数组
    { name: 'tel', args: { message: '手机格式错误' } }
  ]
}

需实现功能如下:

  1. 对目标表单(target)执行配置中指定的验证规则 (validators: 此次配置中只有一个验证规则)
  2. 如验证规则中有 required ,则说明该表单为必填项,必须进行表单验证。
  3. 如验证规则中无 required ,则说明该表单为选填项,只在有输入时才进行表单验证。(该例配置为选填)
  4. 当验证成功时需在 message.target 处显示 message.success 的文本。
  5. 当验证失败时需在 message.target 处显示 验证规则中的指定 的文本。
  6. 失败文本显示优先级同验证规则配置的先后顺序。

以下是具体实现:

_check (config) {
  const
    validatorCfg  = this._validatorConfig,    // 验证器配置
    $target       = $(config.target),         // 验证的表单
    val           = $target.value,            // 验证的value
    $message      = $(config.message.target), // 验证信息显示的地方
    ownValidators = config.validators,        // 所有验证规则
    result        = []                        // 失败信息数组

  // 不是必填项的话,只在有输入内容时进行检查 (默认为不必填)

  let required = false 
  ownValidators.forEach(validator => { // 遍历执行验证器
    if (validator.name === 'required') required = true // 必填
    // 从 Validators 中取出相应的验证规则
    const temp = Validators[validator.name](val, validator.args) // 执行验证器


    // 如验证失败,则存储失败信息

    if ( ! temp.status) result.push( temp.message )     })

    if ( ! required && val.length === 0) return // 不是必填且无输入可跳过检验


    if (result.length > 0) {                                // 有错误信息
      validatorCfg.error && validatorCfg.error($target)     // 失败回调
      $message.textContent = result[0]                      // 显示失败信息
    } else {                                                // 验证通过
      validatorCfg.success && validatorCfg.success($target) // 成功回调
      $message.textContent = config.message.success || ''   // 显示成功信息
    }
  }

其他

// 单个验证 需传入要验证 input 的 id
run (target) {
  // 得到当前要验证的表单的配置
  const curConfig = this._targetConfig.filter(config => config.target === `#${target}`)[0]

  this._check(curConfig)
}
// 执行全局验证
runAll () {
  this._targetConfig.forEach(this._check.bind(this))
}
// 重置表单
reset () {
  this._targetConfig.forEach(config => {
    const
      $target  = $(config.target),
      $message = $(config.message.target)

    $target.value        = ''
    $message.textContent = config.message.placeholder || ''
  })
  this._validatorConfig.reset( this._allTarget ) // 重置回调
}
自此我们的验证插件就写完了,可自行在 validators 中编写更多的验证规则

结语

该表单验证插件创建源于2017百度前端学院的一个作业,代码还不够健壮,还有许多可优化的地方。

以下列举几个优化方向,大家可自行拓展:

  1. 提交表单时应需得到所有表单的验证状态,全通过则提交。
  2. 目前失败信息提示过于单一。
  3. 如表单验证中需与后台通信(如验证用户名是否注册),那么验证器应该支持异步的验证规则。
  4. - 目前会执行所有验证规则,可选择在验证规则失败时,就不再往下继续验证了,以提高性能。

完整代码