您好,登錄后才能下訂單哦!
本篇文章給大家分享的是有關(guān)使用vue怎么構(gòu)建一個動態(tài)表單,小編覺得挺實用的,因此分享給大家學習,希望大家閱讀完這篇文章后可以有所收獲,話不多說,跟著小編一起來看看吧。
概述
后臺管理系統(tǒng)里面有非常多的表單需求,我們希望能夠通過寫一個json格式的數(shù)據(jù),通過vue的循環(huán)動態(tài)地去渲染動態(tài)表單。并且能夠在外部得到渲染出來的表單的數(shù)據(jù),可以對表單進行重置操作。我結(jié)合element ui的控件的下拉框,輸入框,時間選擇控件和vue-treeselect,做了一個動態(tài)表單。
v-model的理解
先簡單講一下vue-model是怎么玩的。其實vue-model相當于給表單元素傳遞一個value,外部監(jiān)聽input事件。所以我們自己封裝表單組件的時候也是可以傳遞一個value值,監(jiān)聽input事件獲取輸入的值。
<input type="text" v-model="something"> <!--等價于--> <input type="text" v-bind:value="something" v-on:input="something = $event.target.value">
封裝表單組件
組件最重要的開發(fā)思想就是設(shè)計好輸入輸出。這里就以下拉框組件為例吧。使用的是element ui的下拉框,進行一個簡單封裝。
輸入:name:每個表單的數(shù)據(jù)標識,如區(qū)域編碼輸入框,父元素應(yīng)該傳遞areaCode過來。
value: 表單選擇/輸入的值,從父元素獲取后賦值給currentValue,通過監(jiān)聽父元素的值實現(xiàn)同步變
化。
options:下拉框要渲染的選項值,一般是個對象數(shù)組。
輸出:onInputEvent,emit一個input事件,讓父元素能夠感知組件的數(shù)據(jù)變化。
也就是可以在組件使用的地方監(jiān)聽input事件
<template> <el-form-item :label="label"> <el-select v-model="currentValue" @input="onInputEvent"> <el-option v-for="item in options" :key="item.value" :label="item.label" :value="item.value"> </el-option> </el-select> </el-form-item> </template> <script> import formMixins from '../../../mixins/form-model' export default { name: "SelectList", props: ['name', 'label', 'value','options'], mixins: [formMixins], data() { return { currentValue: this.value } }, methods: { onInputEvent(value) { this.$emit('input', this.name, value); } }, watch: { value(val) { this.currentValue= val; } } } </script>
一點封裝
由于每個表單組件都是監(jiān)聽父元素的value值變化,數(shù)據(jù)變化時都是觸發(fā)onInputEvent并執(zhí)行this.$emit('input'),所以我們可以把這部分內(nèi)容抽取出來放在mixins里面。
form-model.js
export default { props: ['name', 'value'], data () { return { currentValue: this.value }; }, methods: { onInputEvent(value) { this.$emit('input', this.name, value); }, reset() { this.currentValue = ""; } }, watch: { value (val) { this.currentValue = val; } } };
然后我們的下拉框組件就可以少寫一些共用的代碼,直接用 mixins: [formMixins]
<template> <el-form-item :label="label"> <el-select v-model="currentValue" @input="onInputEvent"> <el-option v-for="item in options" :key="item.value" :label="item.label" :value="item.value"> </el-option> </el-select> </el-form-item> </template> <script> import formMixins from '../../../mixins/form-model' export default { name: "SelectList", props: ['name', 'label', 'value', 'options'], mixins: [formMixins], data() { return { currentValue: this.value } } } </script>
動態(tài)生成表單
這里主要是根據(jù)配置的數(shù)據(jù),循環(huán)生成表單組件。默認提供提交和重置按鈕,如果不需要可以通過slot傳遞其他操作按鈕。這里的要點主要有:
監(jiān)聽表單組件的數(shù)據(jù)變化:
每個表單組件都有一個name標識它的業(yè)務(wù)含義,綁定的數(shù)據(jù)也是formData[field.name],@input事件傳遞updateForm,在updateForm里面更新this.formData[name],保證了this.formData里面的數(shù)據(jù)是和表單組件選擇/填寫的內(nèi)容一致。
重置時改變表單組件的數(shù)據(jù):
因為組件內(nèi)部會監(jiān)聽父元素的value,所以這里只要清空this.formData的值,組件內(nèi)部的數(shù)據(jù)也會跟著清空。
<template> <div> <el-form :inline="true" ref="form" :model="formData" class="demo-form-inline"> <el-col :span="field.cols" v-for="(field, index) in config.fieldsConfig" v-bind:key="index"> <component :key="index" :is="field.fieldType" :label="field.label" :value="formData[field.name]" :multiple="field.multiple" @input="updateForm" v-bind="field" :options="field.options" :ref="field.name" > </component> </el-col> <slot name="buttons"> <el-button type="primary" @click="submit" size="small">{{onSubmitText}}</el-button> <el-button type="default" @click="reset" size="small">{{onResetText}}</el-button> </slot> </el-form> </div> </template> <script> import SelectList from './basicComponent/SelectList' import TextInput from './basicComponent/TextInput' import TimeSelector from './basicComponent/TimeSelector' import SelectTree from './basicComponent/SelectTree' import StaffSelectPopedit from './businessComponent/StaffSelectPopedit' export default { name: "FormGenerator", components: { SelectList, TextInput, TimeSelector, SelectTree, StaffSelectPopedit}, props: ["config", "value"], data() { return { formData: this.value, onSubmitText: this.config.buttons.onSubmitText || '提交', onResetText: this.config.buttons.onResetText || '重置' } }, methods: { updateForm(fieldName, value) { this.formData[fieldName] = value; }, submit() { this.$emit("submit"); }, reset() { for(var name in this.formData) { if(typeof this.formData === "String") { this.formData[name] = ""; } else { this.formData[name] = null; } } } } } </script>
業(yè)務(wù)使用的地方
像下拉框的選擇數(shù)據(jù),這些應(yīng)該是后臺渲染的,所以我們暫時用setTimeout模擬一下。感覺這里this.config.fieldsConfig[4].options寫的不太優(yōu)雅,依賴于配置數(shù)據(jù)的順序肯定不是啥好事情。求大神指點。
<template> <div> <form-generator :config="config" @submit="getFormData" v-model="formData" > </form-generator> </div> </template> <script> import FormGenerator from '../components/form/FormGenerator' export default { name: "FormGeneratorDemo", components: { FormGenerator }, created () { this.queryOrderType(); this.queryAreaTree(); }, data() { return { formData: { orderCode: "", orderType: "", beginTime: "", endTime: "", area: [], staff:"" }, config: { fieldsConfig: [ { name: 'orderCode', label: '定單編碼', fieldType: 'TextInput', cols: 8 }, { name: 'orderType', label: '定單類型', fieldType: 'SelectList', options: [], cols: 8 }, { name: 'beginTime', label: '開始時間', fieldType: 'TimeSelector', cols: 8 }, { name: 'endTime', label: '結(jié)束時間', fieldType: 'TimeSelector', cols: 8 }, { name: 'area', label: '區(qū)域', fieldType: 'selectTree', options: [], multiple: true, cols: 8 }, { name: 'staff', label: '人員選擇', fieldType: 'StaffSelectPopedit', cols: 8 } ], buttons: { onSubmitText: '提交', onResetText: '重置' } } } }, methods: { getFormData() { console.log(this.formData); }, queryOrderType() { setTimeout(() => { this.config.fieldsConfig[1].options = [ { label: 'select1', value: 'key1'}, { label: 'select2', value: 'key2'}, { label: 'select3', value: 'key3'} ]; }, 100) }, queryAreaTree() { this.config.fieldsConfig[4].options = [ { id: 'a', label: 'a', children: [{ id: 'aa', label: 'AA', }, { id: 'ab', label: 'AB', }], }, { id: 'b', label: 'B', }, { id: 'c', label: 'C', } ] } } } </script>
以上就是使用vue怎么構(gòu)建一個動態(tài)表單,小編相信有部分知識點可能是我們?nèi)粘9ぷ鲿姷交蛴玫降?。希望你能通過這篇文章學到更多知識。更多詳情敬請關(guān)注億速云行業(yè)資訊頻道。
免責聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進行舉報,并提供相關(guān)證據(jù),一經(jīng)查實,將立刻刪除涉嫌侵權(quán)內(nèi)容。