// 验证创建Notice的信息
const validate = () => {
// 检测数据合法性
if (!modalConfig.content) {
message.error('重要提示不为空');
return false;
}
if (modalConfig.point > 100) {
message.error('仙岩币不能超过100');
return false;
}
if (!/^1(3|5|7|8|9)[0-9]{9}$/.test(modalConfig.phone)) {
message.error('手机号码格式不正确!');
return false;
}
if (
!/^\w+([+-.]\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)*$/.test(modal Config.email)
) {
message.error('邮箱地址格式不正确!');
return false;
}
if(){}
if(){}
...
return true;
};
1、问题
这样编写代码,的确能够完成业务的需求,能够完成表单的验证,但是存在很多问题,比如:
- validate绑定的函数比较庞大,包含了很多的if-else语句,看着都恶心,这些语句需要覆盖所有的校验规则。
- validate绑定的函数缺乏弹性,如果增加了一种新的校验规则,或者想要把仙岩币数量校验从6改成8,我们都必须深入validate绑定的函数的内部实现,这是违反了开放-封闭原则的。
- 如果程序中增加了另一个表单,这个表单也需要进行一些类似的校验,那我们很可能将这些校验逻辑复制得漫天遍野。
2、用策略模式重构表单校验
- 期望使用:
const validate = () => {
let validator = new Validator()
validator.add(modalConfig.phone, [{
strategy: 'isNonEmpty',
errorMsg: '手机号码不能为空!'
}, {
strategy: 'minLength:11',
errorMsg: '测试手机号码长度最小不为11!',
},{
strategy: 'isMoblie',
errorMsg: '手机号码格式不正确!'
}])
validator.add(modalConfig.email, [{
strategy: 'isNonEmpty',
errorMsg: '邮箱地址不能为空!'
}, {
strategy: 'isEmail',
errorMsg: '邮箱地址格式不正确!'
}])
let errorMsg = validator.start()
return errorMsg
}
- 实现:
/*策略对象*/
const strategies = {
isNonEmpty(value, errorMsg) {
return value === '' ? errorMsg : void 0;
},
minLength(value, length, errorMsg) {
return value.length < length ? errorMsg : void 0;
},
isMoblie(value, errorMsg) {
const regPhone =
/^((13[0-9])|(14[4,5-9])|(15[0-3,5-9])|(16[2,5-7])|(17[0-8])|(18[0-9])|(19[0-3,5-9]))\d{8}$/;
return !regPhone.test(value) ? errorMsg : void 0;
},
isEmail(value, errorMsg) {
const regEmail = /^([a-zA-Z]|[0-9])(\w|\-)+@[a-zA-Z0-9]+\.([a-zA-Z]{2,4})$/;
return !regEmail.test(value) ? errorMsg : void 0;
},
};
/*Validator类*/
class Validator {
constructor() {
this.cache = []; //保存校验规则
}
add(value, rules) {
for (let rule of rules) {
let strategyAry = rule.strategy.split(':'); //例如['minLength',6]
let errorMsg = rule.errorMsg; //'用户名不能为空'
this.cache.push(() => {
let strategy = strategyAry.shift(); //用户挑选的strategy
strategyAry.unshift(value); //把input的value添加进参数列表
strategyAry.push(errorMsg); //把errorMsg添加进参数列表,[dom.value,6,errorMsg]
return strategies[strategy].apply(value, strategyAry);
});
}
}
start() {
for (let validatorFunc of this.cache) {
let errorMsg = validatorFunc(); //开始校验,并取得校验后的返回信息
if (errorMsg) {
//r如果有确切返回值,说明校验没有通过
return errorMsg;
}
}
}
}
3、项目中使用
使用antd组件表单填写 rule规则
如:
const rule = {
name: {
type: 'string',
required: true,
message: '请输入名字'
},
age: [
{
type: 'number',
message: '请输入number',
},
{
message: '年龄必须大于 18',
validator: (rule, value) => value > 18,
},
]};
antd会帮助我们校验 name 是否是 string、age 是否是 number。而 antd其实是用的一个开源的 async-validator 校验库。
4、总结
当出现很多 if else 或者 switch 的时候,我们就可以考虑是否能使用策略模式了。
通过策略模式,我们可以把策略从业务代码中抽离出来,未来扩展的话无需深入到业务代码修改,只需要新增需要的策略,不会使得业务代码变得越来越臃肿。
甚至策略模式也可以更好的进行复用,如果其他业务场景需要类似的策略,直接引入即可,和原有的业务相互独立。
5、规范
复杂表单验证一律走策略模式。
小程序:表单部分较少且已有表单复杂度低,不做限制。
后台:
使用规范 (简单说明,详细可见群治分后台创建活动模块)