用vue写轮子的一些心得(七)——validator表单校验组件

 

需求分析

  • 支持内置校验器,比如:邮箱校验、手机号校验等等;
  • 支持自定义校验器;
  • 支持自定义校验器,并不会造成全局污染,每次new一个新实例;

 

方法实现

1、表单校验基础搭建:

校验器组件逻辑,首先校验必填项,required: true 是否必填,若无填写则直接return报错「必填」。

接着再校验其它内置规则,email、手机号等等。

export default function validate (data, rules) {
    let errors = {}
    rules.forEach(rule => {
        let value = data[rule.key]
        if (rule.required) {
            if (value !== 0 && !value) {
                errors[rule.key] = {required: '必填'}
                return
            }
        }
        if (rule.pattern) {
            if (rule.pattern === 'email') {
                rule.pattern = /^.+@.+$/
            }
            if (rule.pattern.test(value) === false) {
                ensureObject(errors, rule.key)
                errors[rule.key] = {pattern: '格式不正确'}
            }
        }
        if (rule.minLength) {
            if (value.length < rule.minLength) {
                ensureObject(errors, rule.key)
                errors[rule.key].minLength = '太短'
            }
        }
    })
    return errors
}

function ensureObject (obj, key) {
    if (typeof obj[key] !== 'object') {
        obj[key] = {}
    }
}

用法:

let data = {email: ''}
let rules = [{key: 'email', required: true}]
let errors = validate(data, rules)

 2、可将表单校验if逻辑抽离出来:

遍历validators,通过对象key: value 的形式,可在外部自定义校验规则。

export default function validate (data, rules) {
    let errors = {}
    rules.forEach(rule => {
        let value = data[rule.key]
        if (rule.required) {
            let error = validate.required(value)
            if (error) {
                ensureObject(errors, rule.key)
                errors[rule.key].required = error
                return
            }
        }
        // 遍历validators,并逐一调用对应的函数
        let validators = Object.keys(rule).filter(key => key !== 'key' && key !== 'required')
        validators.forEach(item => {
            let error = validate[item] && validate[item](value, rule[item])
            if (error) {
                ensureObject(errors, rule.key)
                errors[rule.key][item] = error
            }
        })
    })
    return errors
}

validate.required = (value) => {
    if (value !== 0 && !value) {
        return '必填'
    }
}
validate.pattern = (value, pattern) => {
    if (value !== 'email') {
        pattern = /^.+@.+$/
    }
    if (pattern.test(value) === false) {
        return '格式不正确'
    }
}
validate.minLength = (value, pattern) => {
    if (value.length < pattern) {
        return '太短'
    }
}

function ensureObject (obj, key) {
    if (typeof obj[key] !== 'object') {
        obj[key] = {}
    }
}

 

3、改写为面向对象方法

每次可new一个新实例,这样好处是并不会造成全局污染。

另外我们可在class中增加一个静态方法 add,用户可自行选择将自定义校验规则添加至新实例上(不共享),或是Validator原型上(共享)。

class Validator {
    static add (name, fn) { //静态方法
        Validator.prototype[name] = fn
    }
    constructor() {}

    validate(data, rules) {
        let errors = {}
        rules.forEach(rule => {
            let value = data[rule.key]
            if (rule.required) {
                let error = this.required(value)
                if (error) {
                    this.ensureObject(errors, rule.key)
                    errors[rule.key].required = error
                    return
                }
            }
            // 遍历validators,并逐一调用对应的函数
            let validators = Object.keys(rule).filter(key => key !== 'key' && key !== 'required')
            validators.forEach(item => {
                if (this[item]) {
                    let error = this[item] && this[item](value, rule[item])
                    if (error) {
                        this.ensureObject(errors, rule.key)
                        errors[rule.key][item] = error
                    }
                } else {
                    throw `不存在的校验器:${item}`
                }
            })
        })
        return errors
    }

    required(value) {
        if (value !== 0 && !value) {
            return '必填'
        }
    }

    pattern(value, pattern) {
        if (value !== 'email') {
            pattern = /^.+@.+$/
        }
        if (pattern.test(value) === false) {
            return '格式不正确'
        }
    }

    minLength(value, pattern) {
        if (value.length < pattern) {
            return '太短'
        }
    }

    ensureObject(obj, key) {
        if (typeof obj[key] !== 'object') {
            obj[key] = {}
        }
    }
}

export default Validator

4、测试用例:

import chai, {expect} from 'chai'
import sinon from 'sinon'
import sinonChai from 'sinon-chai'
chai.use(sinonChai)

import Validator from '../../src/validate'

describe('Validator', ()=> {
    it('存在', ()=> {
        expect(Validator).to.exist
    })
    it('required true 报错', ()=> {
        let data = {
            email: ''
        }
        let rules = [
            {key: 'email', required: true}
        ]
        let validator = new Validator()
        let errors = validator.validate(data, rules)
        expect(errors.email.required).to.eq('必填')
    })
    it('required true 通过', ()=> {
        let data = {
            email: 0
        }
        let rules = [
            {key: 'email', required: true}
        ]
        let validator = new Validator()
        let errors = validator.validate(data, rules)
        expect(errors.email).to.not.exist
    })
    it('attern 正则 报错', ()=> {
        let data = {
            email: '@go.com'
        }
        let rules = [
            {key: 'email', pattern: /^.+@.+$/}
        ]
        let validator = new Validator()
        let errors = validator.validate(data, rules)
        expect(errors.email.pattern).to.eq('格式不正确')
    })
    it('pattern 正则 通过', ()=> {
        let data = {
            email: '1@go.com'
        }
        let rules = [
            {key: 'email', pattern: /^.+@.+$/}
        ]
        let validator = new Validator()
        let errors = validator.validate(data, rules)
        expect(errors.email).to.not.exist
    })
    it('pattern email 报错', ()=> {
        let data = {
            email: '@go.com'
        }
        let rules = [
            {key: 'email', pattern: 'email'}
        ]
        let validator = new Validator()
        let errors = validator.validate(data, rules)
        expect(errors.email.pattern).to.eq('格式不正确')
    })
    it('pattern email 通过', ()=> {
        let data = {
            email: '1@go.com'
        }
        let rules = [
            {key: 'email', pattern: 'email'}
        ]
        let validator = new Validator()
        let errors = validator.validate(data, rules)
        expect(errors.email).to.not.exist
    })
    it('required & pattern', ()=> {
        let data = {
            email: ''
        }
        let rules = [
            {key: 'email', pattern: 'email', required: true}
        ]
        let validator = new Validator()
        let errors = validator.validate(data, rules)
        expect(errors.email.required).to.exist
        expect(errors.email.pattern).to.not.exist
    })
    it('pattern & minLength', ()=> {
        let data = {
            email: ''
        }
        let rules = [
            {key: 'email', pattern: 'email', minLength: 6}
        ]
        let validator = new Validator()
        let errors = validator.validate(data, rules)
        expect(errors.email.minLength).to.exist
        expect(errors.email.pattern).to.exist
    })
    it('自定义测试规则 hasNumber', ()=> {
        let data = {
            email: 'asdfsdf'
        }
        let validator = new Validator()
        validator.hasNumber = (value) => {
            if (!/\d/.test(value)) {
                return '必须含有数字'
            }
        }
        let rules = [{key: 'email', required: true, hasNumber: true}]
        let errors
        let fn = () => {
            errors = validator.validate(data, rules)
        }
        expect(fn).to.not.throw()
        expect(errors.email.hasNumber).to.eq('必须含有数字')
    })

})

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值