背景
現在市面上很多 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)
複製程式碼