讓我們來看看更優雅的表單驗證吧
大家看到這段程式碼有何感想。
有同學會問,這有問題嗎?沒問題。只是不怎麼好看而且有些難以維護。
那麼我們來看看有沒有更好的方式吧。
本文所以的程式碼都在這個連結。
github.com/Link-X/veri…
首先程式碼未動,文件先行
我們先來看下這一坨東西
// 變數
var obj = {
number: 1,
string: 'str',
array: [1, 2, 3],
object: {a: 1},
date: '2018-10-10 08:08'
}
// 校驗規則
var rule = [
number: [
{ required: true, message: '請輸入number' }
],
string: [
{ required: true, type: 'number' message: '請輸入string' }
],
array: [
{ message: '請輸入array' },
{ min: 0, max: 3, message: '最小為0,最大為3' }
],
object: [
{ required: false, message: '請選擇obj', validator: judgeObj }
],
date: [
{ type: 'date' required: true, message: '校驗時間是否合法時,type必須為date' }
]
]
// 自定義校驗規則
function judgeObj (val, cb) {
console.log(val)
if (val.a > 1) {
cb()
} esle {
cb(new Error('不通過'))
}
}
複製程式碼
現在我們的需求是有一個變數,有一個規則,規則對應的key去校驗變數
總之就是配置校驗,減少if else。拯救髮際線。
那麼激動人心的時候到了。開始搬磚寫程式碼
檔案中。為了讓程式碼看著更簡單,我們就當所有的人都不會使用出錯,所以不會對傳入的引數進行校驗是否錯誤,有興趣的同學可以自己提交
首先,定義一個class
class Verify {
constructor (data, rules) {
this.data = null
this.rules = {}
// 每次例項化的時候 把需要校驗的規則和變數匯入
this.$init(data, rules)
}
$init (data, rules) {
// 初始化函式
this.data = data
this.rules = rules
}
iterator (rules) {
// 核心函式,校驗所以的規則
// 狀態變數
let status = {
status: false,
message: '',
key: ''
}
// 迴圈迭代
for (let v of Object.keys(rules)) {
// 這裡我們也簡單點把,兩個規則當一個去校驗
const judge = { ...this.rules[v][0], ...this.rules[v][1] }
console.log(judge) // 此時我們就能獲取到所有的規則啦
console.log(this.data[v]) // 所有的資料
}
}
}
複製程式碼
那麼我們已經完成了初始化,並且能通過遍歷獲取到所有的規則和資料。接下來要做的事情就是,將他們一一對應,並且校驗。
孩兒們,躁動起來
我們重點寫一下這個 iterator 函式,這個寫好了,就完成了一半
// 我們抽出兩個函式來執行,自定義規則校驗吧,不如iterator太大了
class Verify {
...
...
iterator () {
// 核心函式,校驗所以的規則
// 狀態變數
let status = {
status: false,
message: '',
key: ''
}
// 迴圈迭代
for (let v of Object.keys(rules)) {
// 這裡我們也簡單點把,兩個規則當一個去校驗
const judge = { ...this.rules[v][0], ...this.rules[v][1] }
const val = this.data[v]
if (toString.call(judge.validator) === '[object Function]') {
// 自定義規則如果有的直接用自定義規則
// 自定義校驗,對於的處理方式
judge.validator(val, ((status) => {
// 自定義執行函式。目的就是為了把 狀態變數給自定義規則
return (cb) => {
status.status = !!(cb && cb.message)
status.message = cb && cb.message
}
})(status))
} else if (judge.required) {
// 自定義規則必填設定了 true
status.status = this.verifyTop(judge, val) || this.verifyBottom(judge, val)
} else if (!judge.required && judge.min && judge.max) {
// 自定義規則設定裡最大最小值
status.status = val && this.verifyBottom(judge, val)
}
if (status.status) {
// status 為true停止校驗
status.key = v
status.message = status.message ? status.message : judge.message
return
}
}
}
}
複製程式碼
好啦,這個時候核心函式 iteratior 已經寫完了。接下來我們主要的任務就是處理 this.verifyTop 和 this.verifyBottom 這兩個自定義規則校驗。
這裡兩個函式需要用到很多,js變數的型別校驗.
接下來我們新建一個檔案,就叫utils.js吧,把所以的型別校驗都放在那裡。
// 直接上程式碼,簡單粗暴.這些校驗大家應該都不陌生吧。
export const isArray = (data) => {
// 判斷是否陣列的
return Object.prototype.toString.call(data) === '[object Array]'
}
export const isNumber = (data) => {
// 判斷是否數字的
return Object.prototype.toString.call(data) === '[object Number]'
}
export const isString = (data) => {
// 判斷是否字串的
return Object.prototype.toString.call(data) === '[object String]'
}
export const isBoolean = (data) => {
// 判斷是否布林值的
return Object.prototype.toString.call(data) === '[object Boolean]'
}
export const isFunc = (data) => {
// 判斷是否函式的
return Object.prototype.toString.call(data) === '[object Function]'
}
export const isObject = (data) => {
// 判斷是否函式的
return Object.prototype.toString.call(data) === '[object Object]'
}
export const isNull = (data) => {
// 判斷是否null的
return Object.prototype.toString.call(data) === '[object Null]'
}
export const arrayLen = (data) => {
// 判斷陣列有木有長度
return isArray(data) && data.length
}
export const objectLen = (data) => {
// 判斷物件有木有函式
return isObject(data) && Object.keys(data).length
}
export const isDate = (data) => {
// 判斷是否合法時間的,這個有些不嚴謹哈
return !!data && new Date(data).toString() !== 'Invalid Date'
}
export const verifyDate = (val) => {
// 這個是判斷,長度為2的陣列,裡是不是有兩個時間。(時間範圍的時候會用到)
return isArray(val) ? (isDate(val[0]) && isDate(val[1])) : isDate(val)
}
export const getLen = (val) => {
// 獲取變數長度
return val && val.length
}
export const getObjLen = (val) => {
// 獲取物件長度
return Object.keys(val).length
}
export const getNumLen = (val) => {
// 獲取number
return val
}
export const getType = (val) => {
// 獲取變數型別
return (val && val.constructor.name.toLowerCase()) || 'string'
}
export const typeOfS = {
array: isArray,
object: isObject,
number: isNumber,
string: isString,
boolean: isBoolean,
date: verifyDate
}
export const getTypeLen = {
array: getLen,
object: getObjLen,
number: getNumLen,
string: getLen,
date: getLen
}
複製程式碼
接著我們會到 index.js。現在我們再改造一下verify 全貌是是這樣的
import {
objectLen,
isObject,
typeOfS,
isFunc,
getTypeLen,
getType
} from './index.js'
class Verify {
constructor(data, rules) {
this.data = null
this.rules = {}
this.$init(data, rules)
}
$init(data, rules) {
this.data = data
this.rules = rules
}
verifyTop (obj, val) {
// 校驗第一個規則
const type = obj.type ? obj.type : getType(val)
const func = typeOfS[type]
return !(val && func(val))
}
verifyBottom (obj, val) {
// 校驗第二個規則
const section = obj.min && obj.max && obj.type !== 'date'
if (!section) return false
const type = getType(val)
const len = getTypeLen[type](val)
const lenSection = (len >= obj.min && len <= obj.max)
return !lenSection
}
iterator (rules) {
if (!isObject(rules)) {
return
}
let status = {
status: false,
message: '',
key: ''
}
for (let v of Object.keys(rules)) {
const judge = { ...this.rules[v][0], ...this.rules[v][1] }
const val = this.data[v]
if (isFunc(judge.validator)) {
// 自定義規則如果有的直接用自定義規則
// 自定義校驗,對於的處理方式
judge.validator(val, ((status) => {
// 自定義執行函式。目的就是為了把 狀態變數給自定義規則
return (cb) => {
status.status = !!(cb && cb.message)
status.message = cb && cb.message
}
})(status))
} else if (judge.required) {
status.status = this.verifyTop(judge, val) || this.verifyBottom(judge, val)
} else if (!judge.required && judge.min && judge.max) {
status.status = val && this.verifyBottom(judge, val)
}
if (status.status) {
// status 為true停止校驗
status.key = v
status.message = status.message ? status.message : judge.message
return status
}
}
return status
}
validate (cb) {
const status = this.iterator(this.rules)
const result = status.status || status.message
cb({
result: result,
key: status.key,
message: status.message
})
}
}
複製程式碼
okok 大功告成。使用方式
用法
<script src="./utils.js"></script>
<script src="./index.js"></script>
var obj = {
number: 1,
string: 'str',
array: [1, 2, 3],
object: {a: 1},
date: '2018-10-10 08:08'
}
var rule = [
number: [
{ required: true, message: '請輸入number' }
],
string: [
{ required: true, type: 'number' message: '請輸入string' }
],
array: [
{ message: '請輸入array' },
{ min: 0, max: 3, message: '最小為0,最大為3' }
],
object: [
{ required: false, message: '請選擇obj', validator: judgeObj }
],
date: [
{ type: 'date' required: true, message: '校驗時間是否合法時,type必須為date' }
]
]
var judgeObj (val, cb) {
console.log(val)
if (val.a > 1) {
cb()
} esle {
cb(new Error('不通過'))
}
}
var main = new verify(obj, rule);
main.validate((e) => {
if (e.result) {
alert('succes')
return
}
alert('err')
console.log(e.key + 'err' + e.message)
})
main.$init(data, rule)
複製程式碼