让我们来看看更优雅的表单验证吧
大家看到这段代码有何感想。
有同学会问,这有问题吗?没问题。只是不怎么好看而且有些难以维护。
那么我们来看看有没有更好的方式吧。
本文所以的代码都在这个链接。
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)