Element表單驗證(2)
上篇講的是async-validator的基本要素,那么,如何使用到Element中以及怎樣優雅地使用,就在本篇。
上篇講到async-validator由3大部分組成
OptionsValidateRules
基本驗證流程如下
- 先按照rule的規則,制定每個字段的規范,生成rules
- 根據rules生成驗證器
const validator = new Validator(rules) - 驗證器有驗證函數
validator.validate(source, callback) - source中的字段對應規則中的字段,全都通過或出錯后調用callback
上面中的validator.validate對應Element中的this.$refs[refName].validate,只不過被改裝過的。而且在Element中定義<el-form :model='form'> 的:model='form',那個form就是source。source的字段名,如source.name就是form.name,那么只要在<el-form-item prop='name'>設置和source一樣的字段名name,就可以匹配<el-form :rules='rules'>中的rules.name。
很重要的一點,rules.字段名要和source.字段名要一樣才會驗證。
<template>
<el-form :model='form' ref='domForm' :rules='rules'>
<el-form-item prop='name' lable='名字'>
<el-input v-model='form.name'>
</el-form-item>
</el-form>
</template>
export default {
data() {
this.rules = {
name: { type: 'string', required: true, trigger: 'blur' }
}
return {
form: {
name: ''
}
}
},
methods: {
submit() {
this.$refs.domForm.validate(valid => {
if (!valid) {
// 驗證不通過
}
// 驗證通過后的處理...
})
}
}
}
上面中validate(callback)函數已經添加到form元素DOM節點上的屬性中。然后上面還有一個不好的一點。那就是規則的定義方式不夠靈活。
比如我有兩個字段firstName和lastName。firstName是必填的,而lastName是非必填的;且firstName長度要求大於1小於4而lastName要求大於1小於6。那么就要寫兩個不同的規則,現在只是2個字段而已,沒什么,如果有很多個不同要求的字段,那要寫很多個不同的規則,也要寫很多個規則?豈不是很煩?能不能復用?
Rules三種定義方式
- 函數的方式:
{ name(rule, value, callback, source, options) {} } - 對象的方式:
{ name: { type: 'string', required: true } } - 數組的方式:
{ name: [{ type: 'string' }, { required: true }] }
函數的方式很強大,如果需要用到options可以函數的方式,最常用的是對象和數組的方式。現在推薦幾種復用的方法。
簡單的封裝一些常用的規則
// 返回一個規則數組,必填且字符串長度在2~10之間
export const name = (msg, min = 2, max = 10, required = true) => ([
{ required, message: msg, trigger: 'blur' },
{ min, max, message: `長度在${min}~${max}個字符`, trigger: 'blur' }
])
// 郵箱
export const email = (required = true) => ([
{ required, message: '請輸入郵箱', trigger: 'blur' },
{ type: 'email', message: '郵箱格式不對', trigger: 'blur' }
])
/* 自定義驗證規則 */
// 大於等於某個整數
const biggerAndNum = num => (rule, v, cb) => {
const isInt = /^[0-9]+$/.test(v)
if (!isInt) {
return cb(new Error('要求為正整數'))
}
if (v < num) {
return cb(new Error(`要求大於等於${num}`))
}
return cb()
}
export const biggerInt = (int, required = true) => ([
{ required, message: '必填', trigger: 'blur' },
{ validator: biggerAndNum(int), trigger: 'blur' }
])
封裝一個專門創建規則的類,鏈式調用
export default class CreateRules {
constructor() {
super()
this.rules = []
}
need(msg = '必填', trigger = 'blur') {
this.rules.push({
required: true,
message: msg,
trigger
})
return this
}
url(message = '不是合法的鏈接', trigger = 'blur') {
this.rules.push({
type: 'url',
trigger,
message
})
return this
}
get() {
const res = this.rules
this.rules = []
return res
}
}
const createRules = new CreateRules()
//規則
const needUrl = createRules.need().url().get()
const isUrl = createRules.url().get()
// imgUrl必填且是鏈接;href可選不填,如果填寫必須是鏈接
const rules = {
imgUrl: needUrl,
href: isUrl
}
// deep rule 定義
// urls是數組,長度大於1
// urls的元素是鏈接
const urls = ['http://www.baidu.com', 'http://www.baidu.com']
const rules = {
urls: {
type: 'array',
min: 1,
defaultField: isUrl
}
}
