今天写表单校验,查看了一些设计模式的博文,发现好多都是采用策略模式来写的,而不是普通的if-esle-return来写的,看过策略模式之后发现,代码更简洁,复用性更强了,所以自己也动手写了一下,以此记录,留作参考,若有不对的地方,欢迎指正.
假设有两个input框,一个是公司名称,一个是付款卡号,在提交表单的时候,有如下的校验规则:公司名称不能为空,且长度不能超过12;付款户名不能为空且长度不能超过20
公司名称:dealerName 付款户名:payAccount
常规写法:
submitForm:function(){
if(!this.dealerName) {
alert('公司名称不能为空');
return}
if(!this.payAccount) {
alert('付款户名不能为空');
return}
if(this.dealerName.length>12) {
alert('公司名称不能超过12个字符');
return}
if(this.dealerName.length>20) {
alert('付款户名不能超过20个字符');
return}
}
以上代码的缺点就是:1.有一个规则就要写一个if判断,假如遇到一个页面有十几个校验,那就是长长的一串校验规则,代码不简洁
2.同样是校验为空,写了两份,同样是校验字数长度最大值,写了两份,代码冗余
3.假如在别的页面同样也要校验为空,校验字段最大值(一个系统不可能只有一个页面校验字段是否为空吧),那么类似的if判断语句又要写一份,代码复用率不高
4.这次举例的场景没有涉及到,但是可以想象一种情况,手机号校验,手机号校验的规则是会变化的,加入系统多处使用了手机号校验规则,一旦改变,那就是满系统里找手机号的校验规则,然后再一个个改,代码维护太难
介于以上种种缺点,做如下的优化
新建一个validate.js------定义一个Validator类
//validator.js
class Validator{
validateResult = []; //所有规则校验的结果塞到这个数组中
strategys = {//所有的规则定义在这个对象中,如有新的校验规则,在这里面添加,若规则有变动,在这里修改
isEmpty: function(value, errMsg){
if(!value){
return errMsg
}
},
maxLength: function(value, length, errMsg){
if (value.trim().length > length){
return errMsg
}
}
}
check(value,rules){ //value:要校验的值,rules:该值有哪些校验规则,比如dealerName字段,既不能是空的,长度也不能超过12,此时rules中就有两个规则传进来
for( let i=0; i<rules.length; i++){
let rule = rules[i];
let strategyArry = rule.strategy.split(':');
let errMsg = rule.errMsg;
let strategy = strategyArry.shift();
strategyArry.unshift(value);
strategyArry.push(errMsg);
this.validateResult.push( this.strategys[strategy].apply(value,strategyArry)); //遍历规则后,将结果扔进数组
}
}
checkResult(){ //遍历结果数组,若有值,则返回错误提示的信息
for(let i=0; i<this.validateResult.length; i++){
let errMsg = this.validateResult[i];
if(errMsg){
return errMsg
}
}
}
}
export{
Validator
}
在需要使用校验规则的页面调用这个类
//a.vue
import { Validator } from '@/validate.js'
//之前的方法可修改如下
submitForm:function(){
const validator = new Validator();
//公司名称字段校验
validator.check(this.dealerName,[{strategy:'isEmpty',errMsg:'公司名称不能为空'},{strategy:'maxLength:6',errMsg:'公司名称最多6个字符'}]);
//付款户名字段
validator.check(this.payAccount,[{strategy:'isEmpty',errMsg:'付款户名不能为空'},{strategy:'maxLength:10',errMsg:'付款户名最多10个字符'}]);
//加入还有别的字段要校验,则再次调用check()方法
//获取err信息,若有则alert出并return
let errMsg = validator.checkResult();
if(errMsg) {
alert(errMsg);
return
}
}
如果有别的页面要使用,则在别的页面引入validate.js,不需要再写一遍if判断啦
以下是没有单独文件封装的版本,仅作记录
let strategyList = [];
let strategys = {
isEmpty: function(value, errMsg){
if(!value){
return errMsg
}
},
maxLength: function(value, length, errMsg){
if (value.trim().length > length){
return errMsg
}
}
}
function add(value, rules){
for (let i=0;i<rules.length;i++) {
let rule = rules[i];
let strategyArry = rule.strategy.split(':');
let errMsg = rule.errMsg;
strategyList.push(function(){
let strategy = strategyArry.shift();
strategyArry.unshift(value);
strategyArry.push(errMsg);
return strategys[strategy].apply(value,strategyArry)
})
}
}
function checkStrategy(){
for(let i=0; i<strategyList.length; i++){
let errMsg = strategyList[i]();
if(errMsg){
return errMsg
}
}
}
//校验表单数据
//公司名称不能为空且长度不能超过6
add(this.dealerName,[{strategy:'isEmpty',errMsg:'公司名称不能为空'},{strategy:'maxLength:6',errMsg:'公司名称最多6个字符'}]);
//付款卡号不能为空且长度不能超过10
add(this.payAccount,[{strategy:'isEmpty',errMsg:'付款户名不能为空'},{strategy:'maxLength:10',errMsg:'付款户名最多10个字符'}]);
let errMsgF = checkStrategy(strategyList);
if(errMsgF) {
alert(errMsgF);
return
}