According to the requirement of the project, the data should be returned according to the background interface, and the form content should be added dynamically.
Description: This component is based on Ant Design of Vue
Six form controls are currently supported: Text Input, Text Area, Select Input, Select Multiple, Data Picker, and Data Picker Sen.
Text Box
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>
II. Text Domain
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>
3. Drop-down box
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>
Four, date
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>
Form Generation Logic
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 || 'Submission', 50 onResetText: this.config.buttons.onResetText || 'Reset' 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>
Six. Call
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: 'Determine', 21 onResetText: 'cancel' 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>
Background interface data format and page style can be referred to. Please adjust it accordingly according to your own business needs. The following is the background interface data format for my project.
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": "Name of river course (section)", 14 "fieldType": "TextInput", 15 "placeHolder": null 16 }, { 17 "fieldName": "sp_code", 18 "name": "sp_code", 19 "options": [], 20 "label": "Water code", 21 "fieldType": "TextInput", 22 "placeHolder": null 23 }], "fieldClassify": 'Essential information' 24 }, { 25 "fields": [{ 26 "fieldName": "brief_name", 27 "name": "brief_name", 28 "options": [], 29 "label": "Abbreviation of river course (section)", 30 "fieldType": "TextInput", 31 "placeHolder": null 32 }, { 33 "fieldName": "simplegeometry", 34 "name": "simplegeometry", 35 "options": [], 36 "label": "Sparse geometry", 37 "fieldType": "TextInput", 38 "placeHolder": null 39 }], "fieldClassify": 'Attachment information' 40 }, ], 41 buttons: { 42 onSubmitText: 'Determine', 43 onResetText: 'cancel' 44 } 45 }