校驗表單如何擺脫 if else ?

背景

如今市面上不少 ui 框架都有 form 表單校驗,還有些三方庫。個人應用場景是不須要和 ui 綁在一塊兒,傳統的提交校驗 --- 按順序,一個個檢驗。javascript

🌰

好比我有個接口的參數 params1, params2 須要檢驗,不爲空。java

傳統方式固然也是最快的 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)
 }

複製代碼

改進

判斷爲空和正則是最經常使用的功能,優化一下以下ui

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)
複製代碼

說白了無論什麼奇思妙想都是基於策略模式實現的,包括不少庫也是。因此你們想深刻理解推薦你們去看策略模式

相關文章
相關標籤/搜索