使用async-validator編寫(xiě)Form組件的方法
前端開(kāi)發(fā)中,表單的校驗(yàn)一個(gè)很常見(jiàn)的功能,一些 ui 庫(kù)例如ant.design 與Element ui 都實(shí)現(xiàn)了有校驗(yàn)功能的 Form 組件。async-validator 是一個(gè)可以對(duì)數(shù)據(jù)進(jìn)行異步校驗(yàn)的庫(kù),ant.design 與 Element ui 的 Form 組件都使用了 async-validator。本文就簡(jiǎn)單介紹一下 async-validator 的基本用法以及使用該庫(kù)實(shí)現(xiàn)一個(gè)簡(jiǎn)單的有校驗(yàn)功能的 Form 組件。
1. async-validator 的基本用法
async-validator 的功能是校驗(yàn)數(shù)據(jù)是否合法,并且根據(jù)校驗(yàn)規(guī)則給出提示信息。
下面演示一下 async-validator 的最基本用法。
import AsyncValidator from 'async-validator'
// 校驗(yàn)規(guī)則
const descriptor = {
username: [
{
required: true,
message: '請(qǐng)?zhí)顚?xiě)用戶名'
},
{
min: 3,
max: 10,
message: '用戶名長(zhǎng)度為3-10'
}
]
}
// 根據(jù)校驗(yàn)規(guī)則構(gòu)造一個(gè) validator
const validator = new AsyncValidator(descriptor)
const data = {
username: 'username'
}
validator.validate(model, (errors, fields) => {
console.log(errors)
})
當(dāng)數(shù)據(jù)不符合校驗(yàn)規(guī)則時(shí),在 validator.validate 的回調(diào)函數(shù)中,就可以得到相應(yīng)的錯(cuò)誤信息。
當(dāng) async-validator 中常見(jiàn)的校驗(yàn)規(guī)則無(wú)法滿足需求時(shí),我們可以編寫(xiě)自定義的校驗(yàn)函數(shù)來(lái)校驗(yàn)數(shù)據(jù)。一個(gè)簡(jiǎn)單的校驗(yàn)函數(shù)如下。
function validateData (rule, value, callback) {
let err
if (value === 'xxxx') {
err = '不符合規(guī)范'
}
callback(err)
}
const descriptor = {
complex: [
{
validator: validateData
}
]
}
const validator = new AsyncValidator(descriptor)
async-validator 支持對(duì)數(shù)據(jù)異步校驗(yàn),所以在編寫(xiě)自定義校驗(yàn)函數(shù)時(shí),不管校驗(yàn)是否通過(guò),校驗(yàn)函數(shù)中的 callback 都要調(diào)用。
2. 編寫(xiě) Form 組件與 FormItem 組件
現(xiàn)在知道了 async-validator 的使用方法,如何將這個(gè)庫(kù)跟要編寫(xiě)的 Form 組件結(jié)合起來(lái)呢。
實(shí)現(xiàn)思路
用一張圖描述一下實(shí)現(xiàn)思路。

Form 組件
Form 組件應(yīng)該是一個(gè)容器,里面包含不定數(shù)量的 FormItem 或者其他元素??梢允褂?Vue 內(nèi)置的slot 組件來(lái)代表 Form 里面的內(nèi)容。
Form 組件還需要知道包含了多少個(gè)需要校驗(yàn)的 FormItem 組件。一般情況下,父子組件的通信 是通過(guò)在子組件上綁定事件實(shí)現(xiàn)的,但是這里使用 slot,無(wú)法監(jiān)聽(tīng)到子組件的事件。這里可以在 Form 組件上通過(guò)$on 監(jiān)聽(tīng)事件,F(xiàn)ormItem 掛載或者銷毀前觸發(fā) Form 組件的自定義事件即可。
按照這個(gè)思路,我們先編寫(xiě) Form 組件。
<template>
<form class="v-form">
<slot></slot>
</form>
</template>
<script>
import AsyncValidator from 'async-validator'
export default {
name: 'v-form',
componentName: 'VForm', // 通過(guò) $options.componentName 來(lái)找 form 組件
data () {
return {
fields: [], // field: {prop, el},保存 FormItem 的信息。
formError: {}
}
},
computed: {
formRules () {
const descriptor = {}
this.fields.forEach(({prop}) => {
if (!Array.isArray(this.rules[prop])) {
console.warn(`prop 為 ${prop} 的 FormItem 校驗(yàn)規(guī)則不存在或者其值不是數(shù)組`)
descriptor[prop] = [{ required: true }]
return
}
descriptor[prop] = this.rules[prop]
})
return descriptor
},
formValues () {
return this.fields.reduce((data, {prop}) => {
data[prop] = this.model[prop]
return data
}, {})
}
},
methods: {
validate (callback) {
const validator = new AsyncValidator(this.formRules)
validator.validate(this.formValues, (errors) => {
let formError = {}
if (errors && errors.length) {
errors.forEach(({message, field}) => {
formError[field] = message
})
} else {
formError = {}
}
this.formError = formError
// 讓錯(cuò)誤信息的順序與表單組件的順序相同
const errInfo = []
this.fields.forEach(({prop, el}, index) => {
if (formError[prop]) {
errInfo.push(formError[prop])
}
})
callback(errInfo)
})
}
},
props: {
model: Object,
rules: Object
},
created () {
this.$on('form.addField', (field) => {
if (field) {
this.fields = [...this.fields, field]
}
})
this.$on('form.removeField', (field) => {
if (field) {
this.fields = this.fields.filter(({prop}) => prop !== field.prop)
}
})
}
}
</script>
FormItem 組件
FormItem 組件就簡(jiǎn)單很多,首先要向上找到包含它的 Form 組件。接下來(lái)就可以根據(jù) formError 計(jì)算出對(duì)應(yīng)的錯(cuò)誤信息。
<template>
<div class="form-item">
<label :for="prop" class="form-item-label" v-if="label">
{{ label }}
</label>
<div class="form-item-content">
<slot></slot>
</div>
</div>
</template>
<script>
export default {
name: 'form-item',
computed: {
form () {
let parent = this.$parent
while (parent.$options.componentName !== 'VForm') {
parent = parent.$parent
}
return parent
},
fieldError () {
if (!this.prop) {
return ''
}
const formError = this.form.formError
return formError[this.prop] || ''
}
},
props: {
prop: String,
label: String
}
}
</script>
FormItem 在 mounted 與 beforeDestroy 鉤子中還需要觸發(fā) Form 組件的一些自定義事件。
<script>
export default {
// ...
methods: {
dispatchEvent (eventName, params) {
if (typeof this.form !== 'object' && !this.form.$emit) {
console.error('FormItem必須在Form組件內(nèi)')
return
}
this.form.$emit(eventName, params)
}
},
mounted () {
if (this.prop) {
this.dispatchEvent('form.addField', {
prop: this.prop,
el: this.$el
})
}
},
beforeDestroy () {
if (this.prop) {
this.dispatchEvent('form.removeField', {
prop: this.prop
})
}
}
}
</script>
最后新建一個(gè) index.js 導(dǎo)出編寫(xiě)好的組件。
import VForm from './Form.vue'
import FormItem from './FormItem.vue'
export {
VForm,
FormItem
}
3. 使用方式
表單的校驗(yàn)函數(shù)是在 Form 組件中。通過(guò)$ref 可以訪問(wèn)到 Form 組件,調(diào)用 validate 函數(shù),從而獲取到相應(yīng)的校驗(yàn)信息。
使用方法如下:
<template>
<v-form :model="formData" :rules="rules" ref="form">
<form-item label="手機(jī)號(hào)" prop="tel">
<input type="tel" maxlength="11" v-model.trim="formData.tel"/>
</form-item>
<button @click="handleSubmit">保存</button>
</v-form>
</template>
<script>
import { VForm, FormItem } from './common/Form'
export default {
data () {
return {
formData: {
tel: ''
},
rules: {
tel: [
{required: true, message: '您的手機(jī)號(hào)碼未輸入'},
{pattern: /^1[34578]\d{9}$/, message: '您的手機(jī)號(hào)碼輸入錯(cuò)誤'}
]
}
}
},
methods: {
handleSubmit () {
this.$refs.form.validate(errs => {
console.log(errs)
})
}
},
components: {
VForm,
FormItem
}
}
</script>
完整的代碼點(diǎn)擊這里。
4. 總結(jié)
本文簡(jiǎn)單介紹了一下 async-validator 的用法,并實(shí)現(xiàn)了一個(gè)有校驗(yàn)功能的 Form 組件。這里的實(shí)現(xiàn)的 Form 表單存在著很多的不足:(1) 僅僅是在提交表單時(shí)才去校驗(yàn)。(2) FormItem 組件也應(yīng)該根據(jù)校驗(yàn)的結(jié)果調(diào)整 ui,給出相應(yīng)的提示。所以,F(xiàn)orm 組件更適合在交互較少的移動(dòng)端使用。
大家可以根據(jù)這個(gè)實(shí)現(xiàn)思路,根據(jù)應(yīng)用場(chǎng)景,編寫(xiě)定制化更高的 Form 組件。
參考資料
async-validator
Element ui 的 Form組件
Element ui 的 Form 源碼
以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
相關(guān)文章
webpack安裝配置與常見(jiàn)使用過(guò)程詳解(結(jié)合vue)
這篇文章主要介紹了webpack安裝配置與常見(jiàn)使用過(guò)程,主要結(jié)合vue實(shí)現(xiàn),通過(guò)實(shí)例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2020-06-06
vue使用element-ui的el-image的問(wèn)題分析
這篇文章主要介紹了vue使用element-ui的el-image的問(wèn)題分析,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2024-01-01
element-ui?table表格控件實(shí)現(xiàn)單選功能代碼實(shí)例
這篇文章主要給大家介紹了關(guān)于element-ui?table表格控件實(shí)現(xiàn)單選功能的相關(guān)資料,單選框是指在?Element?UI?的表格組件中,可以通過(guò)單選框來(lái)選擇一行數(shù)據(jù)。用戶只能選擇一行數(shù)據(jù),而不能同時(shí)選擇多行,需要的朋友可以參考下2023-09-09
利用Vue的v-for和v-bind實(shí)現(xiàn)列表顏色切換
這篇文章主要介紹了利用Vue的v-for和v-bind實(shí)現(xiàn)列表顏色切換,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2020-07-07
sublime如何配置開(kāi)發(fā)VUE環(huán)境自動(dòng)格式化代碼
這篇文章主要介紹了sublime如何配置開(kāi)發(fā)VUE環(huán)境自動(dòng)格式化代碼問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2024-03-03
前端使用el-table自帶排序功能\后端排序方法實(shí)例
在Vue.js中使用Element UI庫(kù)時(shí)可以通過(guò)el-table組件來(lái)展示表格數(shù)據(jù),并支持列排序,下面這篇文章主要給大家介紹了關(guān)于前端使用el-table自帶排序功能\后端排序的相關(guān)資料,需要的朋友可以參考下2024-08-08
Vue中keep-alive 實(shí)現(xiàn)后退不刷新并保持滾動(dòng)位置
這篇文章主要介紹了Vue中keep-alive 實(shí)現(xiàn)后退不刷新并保持滾動(dòng)位置的相關(guān)知識(shí),本文通過(guò)實(shí)例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2020-03-03

