校验表单如何摆脱 if else ?

背景

现在市面上很多 ui 框架都有 form 表单校验,还有些三方库。我的应用场景是不需要和 ui 绑在一起,传统的提交校验 --- 按顺序,一个个检验。

?

比如我有个接口的参数 params1, params2 需要检验,不为空。

传统方式当然也是最快的 if else
 if(!paramsN) {
     alter(msgN)
     return false
 }
复制代码

策略模式

自从看了策略模式相关的文章受到了一些启发,同时搬下大佬写的自定义校验器,通过 proxy 实现的。
下面瞻仰一下同时看下如何封装

export const validatorCreater = (target, validator) => new Proxy(target, {
 // 保存校验器
 _validator: validator,
 set (target, key, value, receiver) {
   // 如果赋值的属性存在校验器,则进行校验
   if (this._validator[key]) {
     // 遍历其多个子校验器
     for (let validatorStrategy of this._validator[key]) {
       let {errorMsg = '', params = []} = validatorStrategy
       if (!validatorStrategy.validator.call(null, value, ...params)) {
         throw new Error(errorMsg)
       }
     }
   }
   // 赋值语句放最后,如果失败不赋值,如果不存在校验器则赋值
   return Reflect.set(target, key, value, receiver)
 }
})
复制代码

如何使用

  _checkValue = ({ parentId, baseInfo }) => {
   // 这里参考策略模式
   const isNotEmpty = val => val && (val + '').length > 0
   const objEmpty = val => !_.isEmpty(val)
   let validators = {
     baseInfo: [{
       validator: objEmpty,
       errorMsg: 'xxxx'
     }],
     parentId: [{
       validator: isNotEmpty,
       errorMsg: 'xxxx'
     }]
   }
   const checkObj = validatorCreater({}, validators)
   try {
     checkObj.parentId = parentId
     checkObj.baseInfo = baseInfo
   } catch (e) {
     console.warn(e)
     message.error(e.message)
     return false
   }
   return true
 }
复制代码

怎么样,看完是不是受益颇多。用了一段时间思考可不可以通过 es5 的方式来实现一个简版的呢
通过深思熟虑,还是想出了一个雏形方案如下

精简版

export const checkParams = (rules = []) => callback => {
 let checkStatus = true
 try {
   for (let i = 0; i < rules.length; i++) {
     const { fn, value, errorMsg } = rules[i]
     if (!fn(value)) {
       checkStatus = false
       callback && callback(errorMsg)
       break
     }
   }
 } catch (error) {
   console.error(error)
   console.warn(`
     所属值类型------
     fn: 校验函数
     value:所需校验值类型
     errorMsg: 错误信息
   `)
 }
 return checkStatus
}

复制代码

外部调用

 _checkParams = ({ inquiryPrice, inquiryUnit, sellStockNum }) => {
   const isNotEmpty = val => val && (val + '').length > 0
   const rules = [
     { fn: isNotEmpty, value: inquiryPrice, errorMsg: '请填写1' },
     { fn: isNotEmpty, value: inquiryUnit, errorMsg: '请选择2' },
     { fn: isNotEmpty, value: sellStockNum, errorMsg: '请填3' }
   ]
   return checkParams(rules)(message.error)
 }

复制代码

改进

判断为空和正则是最常用的功能,优化一下如下

const _ = require('lodash')
export default (rules = []) => callback => {
 let checkStatus = true
 try {
   for (let i = 0; i < rules.length; i++) {
     const { fn, value, errorMsg = '该参数不合法', required, pattern } = rules[i]
     // 只校验为空
     if (required && !isEmpty(value)) {
       checkStatus = false
       callback && callback(errorMsg)
       break
     }
     // 都需要校验正则了肯定先判空
     if (pattern && isEmpty(value) && !patternCheck(pattern, value)) {
       checkStatus = false
       callback && callback(errorMsg)
       break
     }
     // 自定义校验函数
     if (fn && isEmpty(value) && !fn(value)) {
       checkStatus = false
       callback && callback(errorMsg)
       break
     }
   }
 } catch (error) {
   console.error(error)
   console.warn(`
     所属值类型------
     fn: 自定义校验函数
     value:所需校验值
     errorMsg: 错误信息,
     required: 是否必填,
     pattern: 正则
   `)
 }
 return checkStatus
}
const isEmpty = (value) => {
 const types = ['string', 'number']
 const isExit = types.includes(typeof value)
 if (isExit) {
   return (value + '').length > 0
 } else {
   if (!value) {
     // 判断 null, undefined
     return false
   } else {
     // 判断空数组、空对象
     return !_.isEmpty(value)
   }
 }
}
const patternCheck = (reg, value) => {
 if ((typeof value) === 'string') {
   return reg.test(value)
 } else {
   console.warn('正则只对string有效')
   return false
 }
}
复制代码
使用
const rules = [
   { value: 1, required: true},
   { value: -1, fn: (val) => val > 0, pattern: /^\d{1,}$/ },
   { value: -1, fn: (val) => val > 0 }
   ]
checkParams(rules)(console)
复制代码
说白了不管什么奇思妙想都是基于策略模式实现的,包括很多库也是。所以大家想深入理解推荐大家去看策略模式

转载于:https://juejin.im/post/5c8b686fe51d45453b71f585

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值