vue动态表单

项目需求,需要根据后台接口返回数据,动态添加表单内容

 

说明:此组件基于Ant Design of Vue

目前支持六种表单控件:文本输入框(TextInput)、文本域输入框(TextArea)、下拉选择框(SelectInput)、下拉多选(SelectMultiple)、日期(DataPicker)、日期精确到秒(DataPickerSen

一、文本框

 1 <template>
 2   <a-form-item :label="label" v-bind="formItemLayout">
 3     <a-input
 4       v-decorator="[`${fieldName}`, {initialValue: currentValue}]"
 5       :placeholder="placeHolder"
 6       @input="onInputEvent"
 7     />
 8   </a-form-item>
 9 </template>
10 
11 <script>
12 export default {
13   name: 'TextInput',
14   props: ['name', 'label', 'value', 'options', 'fieldName', 'placeHolder'],
15   data() {
16     return {
17       currentValue: this.value,
18       formItemLayout: {
19         labelCol: {
20           xs: { span: 24 },
21           sm: { span: 8 }
22         },
23         wrapperCol: {
24           xs: { span: 24 },
25           sm: { span: 12 }
26         }
27       }
28     }
29   },
30   methods: {
31     onInputEvent(v) {
32       this.$emit('input', this.name, v.target.value)
33     }
34   },
35   watch: {
36     value(val) {
37       this.currentValue = val
38     }
39   }
40 }
41 </script>

二、文本域

 1 <template>
 2   <a-form-item :label="label" v-bind="formItemLayout">
 3     <a-textarea
 4       v-decorator="[`${fieldName}`, {initialValue: currentValue}]"
 5       :placeholder="placeHolder"
 6       @input="onInputEvent"
 7     />
 8   </a-form-item>
 9 </template>
10 
11 <script>
12 export default {
13   name: 'TextArea',
14   props: ['name', 'label', 'value', 'options', 'fieldName', 'placeHolder'],
15   data() {
16     return {
17       currentValue: this.currentValue,
18       formItemLayout: {
19         labelCol: {
20           xs: { span: 24 },
21           sm: { span: 8 }
22         },
23         wrapperCol: {
24           xs: { span: 24 },
25           sm: { span: 12 }
26         }
27       }
28     }
29   },
30   methods: {
31     onInputEvent(v) {
32       this.$emit('input', this.name, v.target.value)
33     }
34   },
35   watch: {
36     currentValue(val) {
37       this.currentValue = val
38     }
39   }
40 }
41 </script>

三、下拉框

 1 <template>
 2   <a-form-item :label="label" v-bind="formItemLayout">
 3     <a-select
 4       v-decorator="[`${fieldName}`, {initialValue: currentValue}]"
 5       :placeholder="placeHolder"
 6       @change="onInputEvent"
 7     >
 8       <a-select-option v-for="v in options" :key="v.dictId">{{v.dictName}}</a-select-option>
 9     </a-select>
10   </a-form-item>
11 </template>
12 
13 <script>
14 export default {
15   name: 'SelectInput',
16   props: ['name', 'label', 'value', 'options', 'fieldName', 'placeHolder'],
17   data() {
18     return {
19       currentValue: this.value,
20       formItemLayout: {
21         labelCol: {
22           xs: { span: 24 },
23           sm: { span: 8 }
24         },
25         wrapperCol: {
26           xs: { span: 24 },
27           sm: { span: 12 }
28         }
29       }
30     }
31   },
32   methods: {
33     onInputEvent(value) {
34       this.$emit('input', this.name, value)
35     }
36   },
37   watch: {
38     value(val) {
39       this.currentValue = val
40     }
41   }
42 }
43 </script>

四、日期

 1 <template>
 2   <a-form-item :label="label" v-bind="formItemLayout">
 3     <a-date-picker
 4       :defaultValue="moment(currentValue, 'YYYY-MM-DD')"
 5       :placeholder="placeHolder"
 6       @change="onInputEvent"
 7     />
 8   </a-form-item>
 9 </template>
10 
11 <script>
12 import moment from 'moment'
13 
14 export default {
15   name: 'DataPicker',
16   props: ['name', 'label', 'value', 'options', 'fieldName', 'placeHolder'],
17   data() {
18     return {
19       currentValue: this.value,
20       formItemLayout: {
21         labelCol: {
22           xs: { span: 24 },
23           sm: { span: 8 }
24         },
25         wrapperCol: {
26           xs: { span: 24 },
27           sm: { span: 12 }
28         }
29       }
30     }
31   },
32   methods: {
33     moment,
34     onInputEvent(value) {
35       this.$emit('input', this.name, value.format('YYYY-MM-DD'))
36     }
37   },
38   watch: {
39     value(val) {
40       this.currentValue = val
41     }
42   }
43 }
44 </script>

五、表单生成逻辑

 1 <template>
 2   <div class="my-class">
 3     <a-form class="ant-advanced-search-form" :form="form">
 4       <a-row :gutter="24">
 5         <div v-for="(fieldConfig, index) in config.fieldsConfig" :key="index">
 6           <a-col :span="24">
 7             <a-divider>{{fieldConfig.fieldClassify}}</a-divider>
 8           </a-col>
 9           <a-col :span="12" v-for="(field, index) in fieldConfig.fields" :key="index">
10             <component
11               :key="index"
12               :is="field.fieldType"
13               :label="field.label"
14               :fieldName="field.fieldName"
15               :placeHolder="field.placeHolder"
16               :value="value[field.name]"
17               @input="updateForm"
18               v-bind="field"
19               :options="field.options"
20               :ref="field.name"
21             ></component>
22           </a-col>
23         </div>
24       </a-row>
25       <a-row>
26         <a-col :span="24" :style="{ textAlign: 'center', marginTop: '20px' }">
27           <a-button :style="{ marginRight: '8px' }" @click="reset">{{onResetText}}</a-button>
28           <a-button type="primary" @click="submit">{{onSubmitText}}</a-button>
29         </a-col>
30       </a-row>
31     </a-form>
32   </div>
33 </template>
34 <script>
35 import TextInput from './TextInput'
36 import TextArea from './TextArea'
37 import SelectInput from './SelectInput'
38 import SelectMultiple from './SelectMultiple'
39 import DataPicker from './PickerData'
40 import DataPickerSen from './PickerDataSen'
41 
42 export default {
43   name: 'FormGenerator',
44   components: { TextArea, TextInput, SelectInput, SelectMultiple, DataPicker, DataPickerSen },
45   props: ['config', 'value'],
46   data() {
47     return {
48       form: this.$form.createForm(this),
49       onSubmitText: this.config.buttons.onSubmitText || '提交',
50       onResetText: this.config.buttons.onResetText || '重置'
51     }
52   },
53   methods: {
54     updateForm(fieldName, v) {
55       this.value[fieldName] = v
56     },
57     submit() {
58       this.form.validateFields((error, values) => {
59         if (!error) {
60           this.$emit('submit')
61         }
62       })
63     },
64     reset() {
65       this.form.resetFields()
66     }
67   }
68 }
69 </script>
70 
71 <style lang="less" scoped>
72 .my-class {
73   height: 600px;
74   overflow-y: scroll;
75   overflow-x: hidden;
76 }
77 
78 .ant-advanced-search-form .ant-form-item {
79   display: flex;
80 }
81 
82 .ant-advanced-search-form .ant-form-item-control-wrapper {
83   flex: 1;
84 }
85 
86 #components-form-demo-advanced-search .ant-form {
87   max-width: none;
88 }
89 </style>

六、调用

 1 <template>
 2   <div>
 3     <form-generator :config="config" @submit="getFormData" :value="formData"></form-generator>
 4   </div>
 5 </template>
 6 <script>
 7 import { axios } from '@/utils/request'
 8 import FormGenerator from './form/FormGenerator'
 9 
10 export default {
11   name: '',
12   props: {},
13   components: { FormGenerator },
14   data() {
15     return {
16       formData: {},
17       config: {
18         fieldsConfig: [],
19         buttons: {
20           onSubmitText: '确定',
21           onResetText: '取消'
22         }
23       }
24     }
25   },
26   methods: {
27     getFormData() {
28       console.log('formData', this.formData)
29     },
30     queryAllFields() {
31       axios.get(``).then(result => {
32         if (result && result.code === 0) {
33           this.config.fieldsConfig = result.fieldConfig
34         } else {
35           this.$message.error(result.msg)
36         }
37       })
38     }
39   }
40 }
41 </script>
42 <style lang="less" scoped>
43 </style>

后台接口数据格式和页面样式可以参考,请根据自己的业务需求做相应调整,以下为我的项目后台接口数据格式

 1 formData: {
 2     "river_name": '',
 3     "sp_code": '',
 4     "brief_name": '',
 5     "simplegeometry": ''
 6 },
 7 config: {
 8     fieldsConfig: [{
 9         "fields": [{
10             "fieldName": "river_name",
11             "name": "river_name",
12             "options": [],
13             "label": "河道(段)名称",
14             "fieldType": "TextInput",
15             "placeHolder": null
16         }, {
17             "fieldName": "sp_code",
18             "name": "sp_code",
19             "options": [],
20             "label": "水普编号",
21             "fieldType": "TextInput",
22             "placeHolder": null
23         }], "fieldClassify": '基本信息'
24     }, {
25         "fields": [{
26             "fieldName": "brief_name",
27             "name": "brief_name",
28             "options": [],
29             "label": "河道(段)简称",
30             "fieldType": "TextInput",
31             "placeHolder": null
32         }, {
33             "fieldName": "simplegeometry",
34             "name": "simplegeometry",
35             "options": [],
36             "label": "抽稀几何",
37             "fieldType": "TextInput",
38             "placeHolder": null
39         }], "fieldClassify": '附件信息'
40     }, ],
41     buttons: {
42         onSubmitText: '确定',
43         onResetText: '取消'
44     }
45 }

猜你喜欢

转载自www.cnblogs.com/wzq201607/p/vue_genForm.html