ElementUI多個(gè)子組件表單的校驗(yàn)管理實(shí)現(xiàn)
背景
公司項(xiàng)目中所用到的前端框架是Vue.js + ElementUI,因?yàn)轫?xiàng)目的業(yè)務(wù)場(chǎng)景中有很多的大表單,但是ElementUI的表單寫(xiě)法對(duì)于表單的拆分和校驗(yàn)其實(shí)并不是很友好。最初的項(xiàng)目為了方便,常常把多個(gè)表單寫(xiě)在一個(gè).vue組件中,這導(dǎo)致單文件的代碼量巨大,邏輯十分復(fù)雜。目前為了維護(hù)方便,表單的拆分就變得十分重要。
現(xiàn)在做了以下的Demo說(shuō)明我們的業(yè)務(wù)場(chǎng)景,父組件是App.vue,該組件中包含了PersonForm.vue和AdsForm.vue這兩個(gè)子組件(在實(shí)際的業(yè)務(wù)場(chǎng)景中,可能多達(dá)10+表單)?!咎峤弧堪粹o在父組件App.vue中,當(dāng)點(diǎn)擊【提交】按鈕后,應(yīng)該分別校驗(yàn)各個(gè)子組件,如果每個(gè)子組件都校驗(yàn)成功后再進(jìn)行提交。

Demo
PersonForm.vue文件
下面的代碼是PersonForm.vue組件,該表單包括姓名、年齡、性別。我們使用了PersonForm這個(gè)類(lèi)去實(shí)例化組件中的personForm的值。在PersonForm中有個(gè)static方法getRule去獲取校驗(yàn)方法去獲取校驗(yàn)對(duì)象,該校驗(yàn)對(duì)象是ElementUI要求的寫(xiě)法,會(huì)在<el-form>的rules中定義。
<template>
<div class="person-form">
<h2>PersonForm.vue</h2>
<el-form :model="personForm" ref="personForm" :rules="personFormRules">
<!-- 姓名 -->
<el-form-item label="姓名" prop="name">
<el-input v-model="personForm.name"></el-input>
</el-form-item>
<!-- 年齡 -->
<el-form-item label="年齡" prop="age">
<el-input v-model="personForm.age"></el-input>
</el-form-item>
<!-- 性別 -->
<el-form-item label="性別" prop="sex">
<el-radio-group v-model="personForm.sex">
<el-radio label="0">男</el-radio>
<el-radio label="1">女</el-radio>
</el-radio-group>
</el-form-item>
</el-form>
</div>
</template>
<script>
import {validateName, validateAge, validateSex } from '@/lib/validator.js';
// PersonForm的類(lèi)
class PersonForm {
constructor() {
this.name = '';
this.age = null;
this.sex = null;
}
static getRule() {
return {
name: [{ validator: validateName, trigger: 'blur' }],
age: [{ validator: validateAge, trigger: 'blur' }],
sex: [{validator: validateSex, trigger: 'blur'}],
}
}
}
export default {
data() {
return {
personForm: new PersonForm(),
personFormRules: PersonForm.getRule()
}
}
}
</script>
<style>
.person-form {
width: 400px;
height: 350px;
padding: 20px;
border: 1px solid #ccc;
}
</style>
AdsForm.vue文件
下面的代碼是AdsForm.vue組件,該表單包括廣告名和廣告位置。我們使用了AdsForm這個(gè)類(lèi)去實(shí)例化組件中的adsForm的值。在AdsForm中有個(gè)static方法getRule去獲取校驗(yàn)方法去獲取校驗(yàn)對(duì)象。
<template>
<div class="ads-form">
<h2>AdsForm.vue</h2>
<el-form :model="adsForm" ref="adsForm" :rules="adsFormRules">
<!-- 廣告名 -->
<el-form-item label="廣告名" prop="name">
<el-input v-model="adsForm.name"></el-input>
</el-form-item>
<!-- 廣告位置 -->
<el-form-item label="廣告位置" prop="position">
<el-select v-model="adsForm.position">
<el-option value="1" label="左上"></el-option>
<el-option value="2" label="右上"></el-option>
<el-option value="3" label="左下"></el-option>
<el-option value="4" label="右下"></el-option>
</el-select>
</el-form-item>
</el-form>
</div>
</template>
<script>
import { notEmpty, validateName } from '@/lib/validator.js';
class AdsForm {
constructor() {
this.name = '';
this.position = null;
}
static getRule() {
return {
name: [{ validator: validateName, trigger: 'blur' }],
position: [{ validator: notEmpty, trigger: 'blur' }],
}
}
}
export default {
data() {
return {
adsForm: new AdsForm(),
adsFormRules: AdsForm.getRule()
}
}
}
</script>
<style>
.ads-form {
width: 400px;
height: 350px;
padding: 20px;
border: 1px solid #ccc;
margin-left: 30px;
}
</style>
validator.js文件
在PersonForm.vue 和 AdsForm.vue中我們導(dǎo)入了validator.js中的校驗(yàn)方法,這些校驗(yàn)方法中封裝了對(duì)表單屬性值的校驗(yàn)規(guī)則。該文件中的方法在實(shí)際項(xiàng)目中,應(yīng)該使用策略模式再封裝一下。Demo中只有4個(gè)方法,就沒(méi)有再封裝來(lái)干擾讀者理解代碼。
// 驗(yàn)證名字
var validateName = (rule, value, callback) => {
if(!value) {
callback(new Error('名字不能為空'));
} else if(/[a-zA-Z]/.test(value)) {
callback(new Error('請(qǐng)?zhí)顚?xiě)中文名字!'));
} else {
callback();
}
};
// 驗(yàn)證年齡
var validateAge = (rule, value, callback) => {
const toNumberVal = Number(value);
if ((typeof value === 'string' && value === '') || (value === null)) {
callback(new Error('年齡不允許為空'));
} else if (isNaN(toNumberVal)) {
callback(new Error('年齡為數(shù)值類(lèi)型'));
} else if(!(toNumberVal > 0 && toNumberVal <= 120)) {
callback(new Error('年齡范圍應(yīng)該大于一歲且小于等于120歲'));
} else {
callback();
}
}
// 驗(yàn)證性別
var validateSex = (rule, value, callback) => {
if (value === null) {
callback(new Error('性別不允許為空'));
} {
callback();
}
}
// 驗(yàn)證不為空
var notEmpty = (rule, value, callback) => {
if (value === '' || value === null || value === undefined) {
callback(new Error('不允許為空'));
} else {
callback();
}
}
export {
validateName,
validateAge,
validateSex,
notEmpty,
}
App.vue
App.vue是父組件,當(dāng)點(diǎn)擊【提交】按鈕時(shí),應(yīng)該調(diào)用其ElmentUI的this.$refs[formName].validate方法去驗(yàn)證各個(gè)子組件中的表單。但是需要注意的是,該方法是一個(gè)異步方法。
所以這里封裝了一個(gè)getFormPromise去生成Promise對(duì)象,并使用Promise.all去并行調(diào)用返回最終的校驗(yàn)結(jié)果數(shù)組。
<template>
<div class="app">
<h1>App.vue</h1>
<div class="forms-container">
<!-- PersonForm.vue -->
<person-form ref="personFormComp"/>
<!-- AdsForm.vue -->
<ads-form ref="adsFormComp"/>
</div>
<el-button
class="submit-btn"
@click="submitForm"
type="primary">
提交
</el-button>
</div>
</template>
<script>
import PersonForm from '@/components/PersonForm';
import AdsForm from '@/components/AdsForm.vue';
export default {
components: {
'person-form': PersonForm,
'ads-form': AdsForm,
},
methods: {
submitForm() {
// 獲取到組件中的form
const personForm = this.$refs.personFormComp.$refs.personForm;
const adsForm = this.$refs.adsFormComp.$refs.adsForm;
// 使用Promise.all去校驗(yàn)結(jié)果
Promise.all([personForm, adsForm].map(this.getFormPromise)).then(res => {
const validateResult = res.every(item => !!item);
if (validateResult) {
console.log('兩個(gè)表單都校驗(yàn)通過(guò)');
} else {
console.log('兩個(gè)表單未校驗(yàn)通過(guò)');
}
})
},
getFormPromise(form) {
return new Promise(resolve => {
form.validate(res => {
resolve(res);
})
})
}
}
}
</script>
<style>
.app {
border: 1px solid #ccc;
padding: 20px;
width: 900px;
}
.app .submit-btn {
margin-top: 40px;
}
.forms-container {
display: flex;
}
</style>
以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
相關(guān)文章
vue+springboot前后端分離實(shí)現(xiàn)單點(diǎn)登錄跨域問(wèn)題解決方法
這篇文章主要介紹了vue+springboot前后端分離實(shí)現(xiàn)單點(diǎn)登錄跨域問(wèn)題的解決方法,需要的朋友可以參考下2018-01-01
vue實(shí)現(xiàn)書(shū)籍購(gòu)物車(chē)功能
這篇文章主要為大家詳細(xì)介紹了vue實(shí)現(xiàn)書(shū)籍購(gòu)物車(chē)功能,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2021-10-10
vue使用天地圖、openlayers實(shí)現(xiàn)多個(gè)底圖疊加顯示效果
這篇文章主要介紹了vue使用天地圖、openlayers實(shí)現(xiàn)多個(gè)底圖疊加顯示,根據(jù)返回的經(jīng)緯度列表通過(guò)天地圖、openlayers實(shí)現(xiàn)底圖添加,本文通過(guò)示例代碼給大家介紹的非常詳細(xì),需要的朋友參考下吧2022-04-04
vue實(shí)現(xiàn)excel表格的導(dǎo)入導(dǎo)出的示例
本文主要介紹了vue實(shí)現(xiàn)excel表格的導(dǎo)入導(dǎo)出的示例,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2023-04-04
Vue組件大全包括(UI組件,開(kāi)發(fā)框架,服務(wù)端,輔助工具,應(yīng)用實(shí)例,Demo示例)
本文為大家分享了網(wǎng)上比較流行的Vue組件,包括UI組件,開(kāi)發(fā)框架,服務(wù)端,輔助工具,應(yīng)用實(shí)例,Demo示例等開(kāi)源項(xiàng)目,總有一款適合你2018-10-10
Vue實(shí)現(xiàn)頁(yè)面刷新跳轉(zhuǎn)到當(dāng)前頁(yè)面功能
在Vue.js應(yīng)用開(kāi)發(fā)中,有時(shí)候我們需要實(shí)現(xiàn)頁(yè)面的刷新或跳轉(zhuǎn)到當(dāng)前頁(yè)面的功能,這種需求在某些特定場(chǎng)景下非常有用,本文將詳細(xì)介紹如何在Vue中實(shí)現(xiàn)頁(yè)面刷新和跳轉(zhuǎn)到當(dāng)前頁(yè)面的功能,并提供多個(gè)示例和使用技巧,需要的朋友可以參考下2024-10-10

