超轻量代码实现字段校验工具库(移动端)
先附上项目的链接地址:
github: https://github.com/moohng/dan/tree/master/src/validator
动机
有表单的地方必有校验,我们使用不同的框架有不同的校验方法。在PC端基于React
的Ant Design
框架中的Form
表单的功能就十分强大,而在移动端,却很难找到一款能与之匹敌完整框架。移动端比较流行的vux
框架,虽然有的组件自带了校验功能,但然并卵,基本上很难匹配真实项目的需求。
放弃vux
组件自带的校验功能,后来在github
上找到一款比较流行的校验库vee-validate
。这个库做到了与表单组件之间的解耦,确实也能够灵活的实现各式各样的项目需求,但给我的感觉就是有点重。一般来说,移动端的开销越低越好,代码越轻量越好,区区一个校验,实在不忍心用上如此庞大的工具。
思前想后,还不如自己实现一套校验方案。首先校验工具必须要与组件完全解耦,其次校验工具要足够轻量,够用就好。移动端不比PC端,考虑到性能,我们一般校验表单都是在提交的时候进行校验,对不满足要求的字段进行提示(比如:字段组件样式变红,Toast
轻提示等)。
思考
为什么要与组件解耦?
很多时候,我们的表单组件都并非真正意义上的表单,尤其是现在
React
和Vue
带来的组件化时代,很多表单组件都是根据我们自己的需求来封装的,各式各样。如果每封装一个组件,就要带上完整的校验功能,那必然是痛苦的,而且有时候不同的第三方组件库很难实现校验的统一性。所以,我们校验的应该是字段,跟组件本身没有任何关系,尽管我们的字段取值是来自于组件。如此一来,我们的校验工具就适用于任何组件,不管它是否是真正意义上的表单,只要将这个组件跟校验的字段对应起来即可。所以,我们其实是对字段的校验。如何更轻量的实现对字段的校验?
理想的方式应该是这样的:校验结果 = 校验函数(校验目标集合, 校验规则),用代码实现是这样的:
result = validator(target, rules);
。我们只要在提交表单的时候执行校验函数,传入待校验的字段集合和一套校验规则,拿到最后的校验结果。最后,根据结果来做一些后续的处理。目标集合、校验规则和校验结果如何定义?
一个表单存在多个字段,目标集合应该就是一个包含所有字段的一个对象。
1
{ name: '小明', age: 16, email: 'xiaoming@qq.com' }
不同字段往往有不一样的校验规则,校验规则需要对每一个字段进行定义,因而也应该是一个包含所有字段的一个对象。
1
{ name: 规则1, age: 规则2, email: 规则3 }
对规则的定义,我们一般的需求有为空判断、字符串是否满足条件、数字是否在指定范围之内、其他特殊处理。总结起来,校验类型可以归为3类:为空、正则、自定义。为空判断最为常见,单独归为一类;正则表达式可以满足大多数的校验规则,可归为一类;前两种基本上已经满足了百分之七八十的业务场景,所以将剩下的所有校验规则通过自定义函数实现。所以最后每一个字段的校验规则是这样的:
1
2
3
4
5
6
7{
required: true,
pattern: /^QQ\w{2,5}$/,
validator() {
// TODO...
}
}当我们拿到校验结果,我们想要知道校验结果是否通过、校验结果中不通过的字段以及每个字段对应的提示语。所以,校验结果应该是一个包含所有不通过字段的对象。
1
const result = { name: '姓名不能为空', age: '年龄必须大于18岁' }
对于校验结果,我们或许只关心本次校验是否通过,仅仅拿到单纯的校验结果对象不便于操作。因此,
result
应该还有一个hasError()
函数用于返回校验结果是否出错,另外还应有一个first()
函数用于返回第一个错误字段的提示信息。1
2result.hasError() // true
result.first() // 姓名不能为空根据不同的需求,可能还应该提供其他的操作方法。
实现
校验函数(validator)
思路:
- 遍历规则集合,拿每一条规则去校验目标集合中对应的字段;
- 首先是为空校验,空的定义应该是:
null
、undefined
、[]
、{}
、''
等; - 若为空校验不通过,记录提示文本信息并跳过其他校验,否则继续下一个校验;
- 然后是正则校验,同理;
- 最后是自定义校验,自定义校验函数应该传入当前校验的值和整个目标的集合对象(可能会存在与其他字段作比较等)。
1 |
|
校验结果(Result)
我们看到,在validator
函数中,返回了Result
的实例对象。代码很简单:
1 |
|
其实也就是在普通的对象上,扩展(原型上添加)了3个方法。
API
validator
核心校验函数:validator(target: Object, rules: Object) => result: Result
。
target
待校验的目标对象集合:{ name: 'Kevin', age: 18 }
。
rules
校验规则集合:{ name: rule1, age: rule2 }
。
alias
:字段别名。比如:姓名,年龄。作为默认提示语输出,忽略则为key
。trim
:是否忽略字符串首尾空格。默认true
。required
:是否必须。为字符串时作为提示语输出。pattern
:正则表达式。message
:作为校验提示语输出,忽略则输出默认提示语。validate
:自定义校验函数,validate(value, target)
。返回字符串时作为此次校验不通过的提示语输出,或者返回boolean
表示是否通过本次校验,返回fasle
时输出默认提示语。
Result
包括所有不通过校验的字段集合: { name: '姓名不能为空', age: '年龄必须大于12岁' }
。
方法:
result.hasError()
:本次校验是否有错(不通过)。result.first([index: Number])
:校验结果中第一个字段的提示语。index
指定第几个字段,默认为1
。result.firstKey([index: Number])
:校验结果中第一个字段的key
。index
使用同上。
应用
该校验库已经发布到npm仓库,可通过npm
或yarn
工具进行下载。
1 |
|
在Vue
中使用
1 |
|
假如你需要在校验报错之后对相应的组件进行样式上的处理,可通过响应式的result
去完成:
1 |
|
更优雅的做法是通过一个自定义指令
去完成这些事情,比如一些滚动、聚焦、失焦、样式切换等行为。你需要记住的是:你已经拿到了这个校验结果,这个结果已包含了你需要的信息,且是响应式的(在data
中已预先定义),之后的一切处理都可通过这个result
对象去自行扩展。
最后
如果觉得不错,请大家多多支持~