需求分析
- 支持内置校验器,比如:邮箱校验、手机号校验等等;
- 支持自定义校验器;
- 支持自定义校验器,并不会造成全局污染,每次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('必须含有数字')
})
})