开始:传统的表单验证,长篇表单校验起来很费劲
if (value === null || value === '') {
Toast(name + '不能为空')
return false
}
if (key === 'entryUserName') {
if (!PUBLICREG.userNameReg.test(value)) {
Toast('姓名仅支持2-20位中文及字母')
return false
}
}
if (!PUBLICREG.phoneReg.test(value)) {
Toast('请输入正确的手机号')
return false
}
if (key === 'certNo') {
const { showPassportFlag } = componentRule.firstRule
if (!showPassportFlag) {
if (!PUBLICREG.idCardReg.test(value)) {
Toast('请输入正确的身份证证件号码')
return false
}
} else {
if (value < 9) {
Toast('请输入正确的护照证件号码')
return false
}
}
}
....
....
....
此处省略N个 if{...} else {...}
优化:利用策略模式,抽离封装校验规则
第一步:新建validatorRules.js,封装校验规则
import { PUBLICREG } from '@/utils/redisEnum'
const strategies = {
isNotEmpty: function (value, typeName, errorMsg) {
if (value === null || value === '' || value === 'undefined') {
return errorMsg || (typeName ? `${typeName}不能为空` : '不能为空')
}
},
minLength: function (value, length, errorMsg) {
if (value.length < length) {
return errorMsg || `至少输入${length}位字符`
}
},
isMoblePhone: function (value, errorMsg) {
if (!PUBLICREG.phoneReg.test(value)) {
return errorMsg || '手机格式不合法'
}
},
isUserName: function (value, errorMsg) {
if (!PUBLICREG.userNameReg.test(value)) {
return errorMsg || '姓名或昵称仅支持2-20位中文及字母'
}
},
isIdCardNo: function (value, errorMsg) {
if (!PUBLICREG.idCardReg.test(value)) {
return errorMsg || '身份证格式不合法'
}
},
isBankNo: function (value, errorMsg) {
if (!PUBLICREG.bankNoReg.test(value)) {
return errorMsg || '银行卡号格式不合法'
}
},
isNumAndLetter: function (value, errorMsg) {
if (!PUBLICREG.recomedReg.test(value)) {
return errorMsg || '仅支持数字或字母组合'
}
}
}
export default strategies
第二步:新建validator.js,封装Validator,派发校验规则
import strategies from './validatorRules'
export default class Validator {
constructor () {
this.rules = []
}
add (value, rules) {
for (const rule of rules) {
// 取校验参数,例如 ['minLength', 6]
const errorMsg = rule.errorMsg || null
const ruleList = rule.strategy.split(':')
this.rules.push(() => {
const ruleKey = ruleList[0]
ruleList.shift()
ruleList.unshift(value)
ruleList.push(errorMsg)
return strategies[ruleKey].apply(null, ruleList)
})
}
}
run () {
for (const validatorFunc of this.rules) {
const errorMsg = validatorFunc()
if (errorMsg) {
return errorMsg
}
}
},
destory () {
this.rules = []
}
}
第三步:使用
import Validator from 'validator'
const validator = new Validator()
const firstRules = {userName: '', address: '', phone: ''}
validator.add(firstRules.userName, [{
strategy: 'minLength:5',
errorMsg: '至少输入5个字符'
}])
validator.add(firstRules.birthDate, [{
strategy: 'isNoEmpty:出生日期'
}])
validator.add(firstRules.address, [{
strategy: 'isNoEmpty:',
errorMsg: '不能为空'
}, {
strategy: 'minLength:10',
errorMsg: '至少输入10个字符'
}])
validator.add(firstRules.phone, [{
strategy: 'isMoble',
errorMsg: '手机格式不合法'
}])
const result = validator.run()
if (result) {
alert(reslut)
return false
}
缺点:
- 策略相互独立,因此一些复杂的算法逻辑无法共享,造成一些资源浪费;
- 如果用户想采用什么策略,必须了解策略的实现,因此所有策略都需向外暴露,这是违背迪米特法则/最少知识原则的,也增加了用户对策略对象的使用成本。
优点:
- 策略之间相互独立,但策略可以自由切换,这个策略模式的特点给策略模式带来很多灵活性,也提高了策略的复用率;
- 如果不采用策略模式,那么在选策略时一般会采用多重的条件判断,采用策略模式可以避免多重条件判断,增加可维护性;
- 可扩展性好,策略可以很方便的进行扩展;