策略模式优化表单校验

895 阅读4分钟
背景

​ 在最近做的一个项目当中,需要做到表单字段的校验,当用户输入的字段不符合要求时,提示错误信息。并且需要用户点击对应错的字段,错误提示才消失。(例如提示手机号错误,只能点击手机号输入框时,错误才消失)。

预览

在表单页面中,请求接口前前端都会做一些校验,例如输入不能为空、输入格式不正确等等。

1.传统方式if-else

在我的之前的版本实现当中,用的最多的是if-els(没有if-else判断不了的事情)。

if (!companyEmail) {
  return false;
} else if (!companyPassword) {
  return false;
}

If-else确实很方便就完成了们的需求,但是如果需要校验的字段不止两个,或者校验要求越来越多的话,用if-else就显得过于臃肿了,例如:

if (value1 == "") {
  console.log("value1不能为空");
} else if (value1.length < 6) {
  console.log("value1不能少于6位");
} else if (!(/'某正则'/.test(value1))) {
  console.log("value1不符合规则");
}

光一个字段就已经有3个if-else了,如果字段多的话,这段if-else语句也会越来越长。

2.使用策略模式优化表单校验

js中的策略模式关键字:策略和业务分离

首先先定义一些我们验证的规则:

const strategies = {
  	/*判断是否为空*/
    isNonEmpty([value, errorMsg]) {
      return value == '' ?
        errorMsg : ''
    },
  	/*判断最小程度*/
    minLength([value, length, errorMsg]) {
      return value.length < length ?
        errorMsg : ''
    },
  	/*判断最大长度*/
    maxLength([value, length, errorMsg]) {
      return value.length > length ?
        errorMsg : ''
    },
    /*判断是否手机号*/  
    isMoblie([value, errorMsg]) {
      return !/^1(3|4|5|6|7|8|9)[0-9]{9}$/.test(value) ?
        errorMsg : ''
    },
    /*判断邮箱号*/
    isEmail([value, errorMsg]) {
      return !/^\w+([+-.]\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)*$/.test(value) ?
        errorMsg : ''
    },
  	......//其他验证规则
}

然后是Validator类的实现:

class Validator {
    constructor() {
        this.cache = [] //保存校验规则
    }
    add(ruleFiled, rules) {
        let key = Object.keys(ruleFiled);//取出当前key值
        let value = Object.values(ruleFiled);//取出当前value值
        for (let rule of rules) {
            let strategyAry = rule.strategy.split(':') //将strategy于参数分开,如minLength:6
            let errorMsg = rule.errorMsg; //如:'用户名不能为空'
            let strategy = strategyAry.shift() //取出strategy
            strategyAry.unshift(value) //把value添加进参数列表
            strategyAry.push(errorMsg) //把errorMsg添加进参数列表,[value,6,errorMsg]
            let result = strategies[strategy](strategyAry)//要么返回errorMsg,要么返回''字符串
            this.cache.push({ [key]: result });//根据当前key动态将一个对象存入校验规则数组当中,例如[{'telephone':'手机号错误,请重新输入'}]
        }
    }
    start() {
        let length = this.cache.length;
        for (let index = 0; index < length; index++) {
            const element = this.cache[index];//此时element是一个对象
            const key = Object.keys(element);
            //如果有确切返回值,说明校验没有通过
            if (element[key]) {
                //返回错误信息:{errorMsg: '手机号不能为空', errorType: telephone}
                return { errorMsg: element[key], errorType: key }
            }
        }
    }
}

add函数有两个参数,第一个是object,里面是当前验证的字段名以及value值,记录字段名是为了方便返回客户端当前出错的字段是哪个字段 如:{telephone:'1234567'}。第二个参数是需要校验的规则,例如客户端需要判断是否为空。通过this.cache保存了所有经过的之前定义的规则的结果。(每个验证的规则要么返回报错信息,要么返回空字符串)。

start函数用于启动遍历this.cache里面的值,如果判断里面元素的vue有确切值,说明校验不通过。

客户端调用代码如下:

import { Validator } from "./validator";

validator.add({ telephone }, [
  {
    strategy: "isNonEmpty",
    errorMsg: "请输入手机号"
  },
  {
    strategy: "isMoblie",
    errorMsg: "手机号错误,请重新输入"
  }
]);

Validator.js代码:

/*
 * @Date: 2020-04-27 22:51:44
 * @LastEditTime: 2020-04-29 15:53:24
 */

/*校验规则对象*/
const strategies = {
  isNonEmpty([value, errorMsg]) {
    return value == '' ?
      errorMsg : ''
  },
  minLength([value, length, errorMsg]) {
    return value.length < length ?
      errorMsg : ''
  },
  maxLength([value, length, errorMsg]) {
    return value.length > length ?
      errorMsg : ''
  },
  isMoblie([value, errorMsg]) {
    return !/^1(3|4|5|6|7|8|9)[0-9]{9}$/.test(value) ?
      errorMsg : ''
  },
  isEmail([value, errorMsg]) {
    return !/^\w+([+-.]\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)*$/.test(value) ?
      errorMsg : ''
  }
}


/*Validator类*/
class Validator {
  constructor() {
    this.cache = [] //保存校验规则
  }
  add(ruleFiled, rules) {
    let key = Object.keys(ruleFiled);//取出当前key值
    let value = Object.values(ruleFiled);//取出当前value值
    for (let rule of rules) {
      let strategyAry = rule.strategy.split(':') //将strategy于参数分开,如minLength:6
      let errorMsg = rule.errorMsg; //如:'用户名不能为空'
      let strategy = strategyAry.shift() //取出strategy
      strategyAry.unshift(value) //把value添加进参数列表
      strategyAry.push(errorMsg) //把errorMsg添加进参数列表,[value,6,errorMsg]
      let result = strategies[strategy](strategyAry)//要么返回errorMsg,要么返回''字符串
      this.cache.push({ [key]: result });//根据当前key动态将一个对象存入校验规则数组当中,例如[{'telephone':'手机号错误,请重新输入'}]
    }
  }
  start() {
    let length = this.cache.length;
    for (let index = 0; index < length; index++) {
      const element = this.cache[index];//此时element是一个对象
      const key = Object.keys(element);
      //如果有确切返回值,说明校验没有通过
      if (element[key]) {
        //返回错误信息:{errorMsg: '手机号不能为空', errorType: telephone}
        return { errorMsg: element[key], errorType: key }
      }
    }
  }
}
export { Validator }

写在最后

代码基于很多篇文章的代码再结合自己的项目需求加了一部分代码,就不一一列出了。

当然,也需要结合实际需求,如果两三个if-else能解决的问题,就不用大刀阔斧的写各种方法了,显得杀鸡用宰牛刀的感觉。