概述
后台管理系统里面有非常多的表单需求,我们希望能够通过写一个json格式的数据,通过vue的循环动态地去渲染动态表单。并且能够在外部得到渲染出来的表单的数据,可以对表单进行重置操作。我结合element ui的控件的下拉框,输入框,时间选择控件和vue-treeselect,做了一个动态表单。
v-model的理解
先简单讲一下vue-model是怎么玩的。其实vue-model相当于给表单元素传递一个value,外部监听input事件。所以我们自己封装表单组件的时候也是可以传递一个value值,监听input事件获取输入的值。
<input type="text" v-model="something"> <!--等价于--> <input type="text" v-bind:value="something" v-on:input="something = $event.target.value">
封装表单组件
组件最重要的开发思想就是设计好输入输出。这里就以下拉框组件为例吧。使用的是element ui的下拉框,进行一个简单封装。
输入:name:每个表单的数据标识,如区域编码输入框,父元素应该传递areaCode过来。
value: 表单选择/输入的值,从父元素获取后赋值给currentValue,通过监听父元素的值实现同步变
化。
options:下拉框要渲染的选项值,一般是个对象数组。
输出:onInputEvent,emit一个input事件,让父元素能够感知组件的数据变化。
也就是可以在组件使用的地方监听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>
一点封装
由于每个表单组件都是监听父元素的value值变化,数据变化时都是触发onInputEvent并执行this.$emit('input'),所以我们可以把这部分内容抽取出来放在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>
动态生成表单
这里主要是根据配置的数据,循环生成表单组件。默认提供提交和重置按钮,如果不需要可以通过slot传递其他操作按钮。这里的要点主要有:
监听表单组件的数据变化:
每个表单组件都有一个name标识它的业务含义,绑定的数据也是formData[field.name],@input事件传递updateForm,在updateForm里面更新this.formData[name],保证了this.formData里面的数据是和表单组件选择/填写的内容一致。
重置时改变表单组件的数据:
因为组件内部会监听父元素的value,所以这里只要清空this.formData的值,组件内部的数据也会跟着清空。
<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>
业务使用的地方
像下拉框的选择数据,这些应该是后台渲染的,所以我们暂时用setTimeout模拟一下。感觉这里this.config.fieldsConfig[4].options写的不太优雅,依赖于配置数据的顺序肯定不是啥好事情。求大神指点。
<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: '结束时间', fieldType: 'TimeSelector', cols: 8 }, { name: 'area', label: '区域', 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>
大概就是这样的思路,我们希望我们只要写上面那样子的配置数据就可以动态生成各种这样的表单组件,不用写一大堆重复代码。如果有更好的解决办法,欢迎和我联系。另外,代码路径https://github.com/supportlss/vue-dynamic-form
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。
免责声明:本站资源来自互联网收集,仅供用于学习和交流,请遵循相关法律法规,本站一切资源不代表本站立场,如有侵权、后门、不妥请联系本站删除!
更新日志
- 凤飞飞《我们的主题曲》飞跃制作[正版原抓WAV+CUE]
- 刘嘉亮《亮情歌2》[WAV+CUE][1G]
- 红馆40·谭咏麟《歌者恋歌浓情30年演唱会》3CD[低速原抓WAV+CUE][1.8G]
- 刘纬武《睡眠宝宝竖琴童谣 吉卜力工作室 白噪音安抚》[320K/MP3][193.25MB]
- 【轻音乐】曼托凡尼乐团《精选辑》2CD.1998[FLAC+CUE整轨]
- 邝美云《心中有爱》1989年香港DMIJP版1MTO东芝首版[WAV+CUE]
- 群星《情叹-发烧女声DSD》天籁女声发烧碟[WAV+CUE]
- 刘纬武《睡眠宝宝竖琴童谣 吉卜力工作室 白噪音安抚》[FLAC/分轨][748.03MB]
- 理想混蛋《Origin Sessions》[320K/MP3][37.47MB]
- 公馆青少年《我其实一点都不酷》[320K/MP3][78.78MB]
- 群星《情叹-发烧男声DSD》最值得珍藏的完美男声[WAV+CUE]
- 群星《国韵飘香·贵妃醉酒HQCD黑胶王》2CD[WAV]
- 卫兰《DAUGHTER》【低速原抓WAV+CUE】
- 公馆青少年《我其实一点都不酷》[FLAC/分轨][398.22MB]
- ZWEI《迟暮的花 (Explicit)》[320K/MP3][57.16MB]