扩展element-ui校验规则
1.现状分析
我们使用的前端框架目前主要是element-ui和vant,老版本的甚至还有使用vux.不管那个框架在使用时都涉及到对输入表单的校验.
翻看官方的文档发现底层实现大多都是利用相应的验证框架, 对应版本如下:
element-ui 2.15.1 ====> async-validator 1.8.5, 最新版本是3.5.1
vux 2.9.4 ====> "validator": "^9.3.0",
vant 2.12.14 ====> 没有内置验证框架,不过可以自定义
常用的验证框架也不少,vuelidate, vee-validate, validator, async-validator
其中pc端主要是用element-ui组件库,对表单的验证规则限制比较多,比如像身份证验证,手机号码验证,虽然可以通过正则表达式来自己定义.
总感觉还是比较麻烦,如果能够扩展,自己定义一些规则, 把常用的验证抽取出来统一放到一个文件,统一设置,然后统一使用,
然后在程序的任何地方都能够应用就比较完美了.
比如要验证身份证号码: 只需要指定以下规则
{ type: 'id', message: '身份证号码格式错误', trigger:['blur','change']},
比如要验证手机号码: 只需要指定以下规则
{ type: 'mobile', message: '手机号码格式错误', trigger:['blur','change']},
这样岂不是很爽啊.
2.分析问题
我翻遍官网的文档(element-ui,async-validator),都没有找到如何扩展form已有的校验规则.
不得已只好找出async-validator源代码来分析, 大概浏览了一下,发现有以下的代码片段
在async-validator源码的src/index.js中发现了这样一个静态函数,似乎是注册某种类型的校验器的.
Schema.register = function register(type, validator) {
if (typeof validator !== 'function') {
throw new Error('Cannot register a validator by type, validator is not a function');
}
validators[type] = validator;
};
发现validators对象是系统定义的validator的容器,框架自带的类型校验器都在该对象中.
而我们看到Schema.register函数也是把传入的校验器保存到这个对象容器中.
这个函数在框架中都没找到地方调用,会不会就是提供给我们扩展的呢.
可不可以我们自定义一些validator通过调用该方法放到容器中就生效了呢.
假设如果成立,那就要解决以下两个问题:
1.validator怎么编写
2.validator怎么注册
validator编写
通过观察系统自带的validator发现:
这个跟我们平时在使用校验规则的时候,自己定义的写法完全相同.
validator 本质上就是个函数,接受和待验证的输入框相关的参数.
找一个比较简单的系统默认的校验器来研究研究,比如number校验器,在源码src/validator/number.js中
内容如下:
/**
* 校验一个数字
* @param rule 单条的校验规则.其实就是使用是自己设置的规则对象
* @param value 就是你在输入框中输入的值
* @param callback 回调函数.有参数表示校验失败,没参数表示成功.
* @param source 就是检查的哪个属性的那个取值,是一个对象.
* @param options 校验时的选项参数.包含
* {
* messages: '', //默认错误消息提示,这是个对象,包含默认情况下其他的type的校验器的提示信息
* firstFields: true // 第一个字段检查之如果错误,就不检查后面的字段
* }
*/
function number(rule, value, callback, source, options) {
const errors = [];
const validate = rule.required || (!rule.required && source.hasOwnProperty(rule.field));
if (validate) {
if (isEmptyValue(value) && !rule.required) {
return callback();
}
rules.required(rule, value, source, errors, options);
if (value !== undefined) {
rules.type(rule, value, source, errors, options);
rules.range(rule, value, source, errors, options);
}
}
callback(errors);
}
就是在这个函数中做逻辑校验的,经验证对于以下规则是有效的.
{ type: 'number', message: '必须是数字格式', trigger:['blur','change']},
validator注册
发现系统自带的validator都导入到validators对象中了,并没有调用注册函数.
估计是我们外部扩展的才需要定义调用注册函数来注册.
Schema.register('id',validId);
这里的第一个参数就是type,第二个参数就是validator函数名了.
3.最佳实践
虽然理论上没问题,总得实践下
1.编写扩展校验器并注册
在项目的/src/plugins/validate.js文件中增加以下内容:
// 导入框架
import Schema from 'async-validator';
// 身份证号码校验器
function validId(rule, value, callback){
if(value){ // '', undefined
let reg=/^[1-9]\d{5}(18|19|([23]\d))\d{2}((0[1-9])|(10|11|12))(([0-2][1-9])|10|20|30|31)\d{3}[0-9Xx]$/;
if(!reg.test(value)){callback(new Error('身份证号码不正确'));}
}else{
callback();
}
}
// 注册身份证号码校验器
Schema.register('id',validId);
2.导入扩展校验器
在项目的src/main.js文件中增加一行内容
import '@/plugins/validate'; //自定义校验
3.在组件中使用
<el-form :rules="rules" ref="ruleForm" :model="form" label-width="120px" size="small">
<el-form-item label="名称" prop="ident">
<el-input placeholder="英文名称" v-model="form.ident" style="width:48%" required/>
</el-form-item>
</el-form>
<script>
export default {
data() {
form: { ident: ''},
rules: {
ident: [
{ type: 'id', message: '身份证号码格式错误', trigger:['blur','change']},
{ required: true, message: '必须输入身份证号码', trigger:['blur','change']},
]
}
}
}
</script>
{ type: ‘id’, message: ‘身份证号码格式错误’, trigger:[‘blur’,‘change’]},
只需要定义校验规则{type: ‘id’}, 就能使用到我们在全局扩展的校验器.
这种方式确实比在每个表单都去定义要方便多了.
经过验证确实证明我们的猜想是正确的.
4.总结
只需要写好自己的validator并调用框架提供的注册函数注册的校验器,即可在全局使用.
把我们项目中用到的校验规则统一写成校验器.应该能省不少事情.