需求分析
- 支持內置校驗器,比如:郵箱校驗、手機號校驗等等;
- 支持自定義校驗器;
- 支持自定義校驗器,並不會造成全局污染,每次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: '[email protected]'
}
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: '[email protected]'
}
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('必須含有數字')
})
})