vue构建动态表单的方法示例

后台管理系统里面有非常多的表单需求,我们希望能够通过写一个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"> <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> <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>

业务使用的地方

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:http://www.heiqu.com/b202f84e81d933fc81f9ccdc421e0ca8.html