Vue + ElementUI implements form dynamic rendering and visualized configuration. vueelementui
Dynamic rendering is an asynchronous data, which is about long:
{"Inline": true, "labelPosition": "right", "labelWidth": "", "size": "small", "statusIcon": true, "formItemList ": [{"type": "input", "label": "name", "disable": false, "readonly": false, "value ":"", "placeholder": "Enter name", "rules": [], "key": "name", "subtype": "text" },{ "type ": "radio", "label": "gender", "value": "", "button": false, "border": true, "rules": [], "key": "gender", "options": [{"value": "1", "label": "male", "disabled": false }, {"value": "0", "label": "female", "disabled": false}]}
Then you need to render the json as follows:
The Data Length of the final submitted form is as follows:
{ "name": "Genji", "gender": "1"}
Then our goal is to encapsulate such a component:
<dynamic-form :config="someConfig" v-model="someData" />
Implementation
Before starting, You Need To Know How v-model works:
<input v-model="something">
This is just the syntax sugar in the following example:
<input :value="something" @input="something = $event.target.value">
After learning about this, let's implement this component step by step.
First, forward the configuration to el-form:
<template> <el-form class="dynamic-form" :inline="formConfig.inline" :model="value" :label-position="formConfig.labelPosition" :label-width="formConfig.labelWidth" :size='formConfig.size' :status-icon="formConfig.statusIcon"> <slot/> </el-form></template><script>export default { props: { formConfig: { type: Object, required: true }, value: { type: Object, required: true } },}</script>
Step 2: Set the default value.
Because in each form-item
A v-model is required, so before rendering, ensure that each field has a value. Note that do not directly modify the prop passed by the parent component in the component, so we use {...this.value}
Copy a copy quickly. Do not forget to notify the parent component. The Code is as follows:
Export default {props: {formConfig :{...}, value :{...},}, methods: {setDefaultValue () {const formData = {... this. value} // set the default value this. formConfig. formItemList. forEach ({key, value}) ==>{ if (formData [key] === undefined | formData [key] === null) {formData [key] = value}) this. $ emit ('input', formData) }}, mounted () {this. setDefaultValue ()},}
Step 3: render form-item.
How can we render the following data as a familiar el-form-item?
{"Type": "input", "label": "name", "disable": false, "readonly": false, "value": "", "placeholder ": "Enter name", "rules": [], "key": "name", "subtype": "text "}
First, the built-in component of vue may be written as follows:
<el-form-item> <component :is="`el-${item.type}`" /></el-form-item>
Second, use v-if to judge one by one:
<El-form-item> <el-input v-if = "item. type = 'input' "/> <span v-else> unknown control type </span> </el-form-item>
Considering that the processing logic of each form control varies widely, the author adopted the second method.
According to this idea, we encapsulatedynamic-form-item
, Receives an item and renders an el-form-item:
<Template> <el-form-item: rules = "item. rules ": label =" item. label ": prop =" item. key "> <el-input v-if =" item. type = 'input' "v-bind =" $ attrs "v-on =" $ listeners ": type =" item. subtype ": placeholder =" item. placeholder ": disabled =" item. disable ": readonly =" item. readonly ": autosize =" item. autosize "> </el-input> <el-select v-else-if =" item. type = 'select' "v-bind =" $ attrs "v-on =" $ listeners ": multiple =" item. multiple ": Disabled = "item. disabled ": multiple-limit =" item. multipleLimit "> <el-option v-for =" o in item. options ": key =" o. value ": label =" o. label ": value =" o. value ": disabled =" o. disabled "> </el-option> </el-select> <! -- Suddenly miss JSX -->... <span v-else> unknown control type </span> </el-form-item> </template> <script> export default {props: {item: {type: object, required: true }}</script>
Tips: Used v-bind="$attrs" v-on="$listeners"
You can easily forward v-model
Command. For more information, see vue advanced components.
Finally, we can output a complete form cyclically:
<dynamic-form-item v-for="item in formConfig.formItemList" :key="item.key" v-if="value[item.key]!==undefined" :item="item" :value="value[item.key]" @input="handleInput($event, item.key)" />
Not available herev-model="value[item.key]"
As mentioned above, the props cannot be directly modified in the component, so we will forward it here.
Methods: {handleInput (val, key) {// here, element-ui does not report the event, and this is the value. $ emit ('input ',{... this. value, [key]: val})}, setDefaultValue (){...}},
Complete Code address:src/components/dynamic-form/form.vue
Extended Functions
1. Number Display Unit, limited to decimal places
Element-ui does not do this function, but I think it is quite common, so using el-input to manually encapsulate an input-number:
<! -- Common usage --> <input-number v-model = "someNumber": min = "1": max = "99 ": decimal1 = "2" append = ""> </input-number> <! -- Application in dynamic-form-item --> <input-number v-else-if = "item. type = 'number' "v-bind =" $ attrs "v-on =" $ listeners ": min =" item. min ": max =" item. max ": decimal1 =" item. decimal1 ": append =" item. append ": prepend =" item. prepend ": disabled =" item. disabled "> </input-number>
Complete code:src/components/dynamic-form/input-number.vue
2. asynchronous Verification
Thanks to async-validator, we can easily customize verification rules.
In configuration
{"Type": "input ",... "rules": [{"SQL": "SELECT {key} FROM balabala", "message": "xx occupied", "trigger": "blur"}]}
In dynamic-form-item
In the component, traverse item. rules and convert SQL verification to a custom validator function:
<Template> <el-form-item: rules = "Rules">... </el-form-item> </template> <script> import request from '@/utils/request' export default {props: {item :{...}}, computed: {Rules () {const rules = this. item. rules if (rules = undefined) return undefined const R = [] rules. forEach (rule => {if (rule. SQL) {const validator = (rule2, value, callback) => {// modify the request ('/api/validate', 'post', {k Ey: rule2.field, value, SQL: rule. SQL. replace (/{key}/ig, rule2.field)}). then (res => {callback (! Res | undefined )}). catch (err => {this. $ message. error (err. message) callback (false)} R. push ({validator, message: rule. message, trigger: 'blur'})} else {R. push (rule) }}) return R }},}</script>
3. Fast configuration of provincial and municipal areas
Thanks to the author of element-china-area-data.
In Configuration:
{ "type": "cascader", ... "areaShortcut": "provinceAndCityData"}
In the dynamic-form-item component:
<template> <el-form-item> ... <el-cascader :options="item.options || require('element-china-area-data')[item.areaShortcut]" ></el-cascader> </el-form-item></template>
4. Remote Loading options
Including but not limited to radio, checkbox, cascader, select
In Configuration:
{ "type": "checkbox", ... "optionsUrl": "/api/some/options"}
In the dynamic-form-item component:
<Template> <el-form-item>... <el-select> <el-option v-for = "o in item. options | ajaxOptions "> </el-option> </el-select> </el-form-item> </template> <script> import request from '@/utils /request 'export default {props: {item :{...}}, computed :{...}, data () {return {ajaxOptions: [] }}, created () {const {optionsUrl, key, type} = this. item if (optionsUrl) {// modify the request ('$ {optionsUrl }? Key =$ {key} ', 'get '). then (res => {this. ajaxOptions = res }). catch (err => {this. $ message. error (err. message)}) }}</script>
Summary
The above section describes how to use Vue + ElementUI to implement dynamic form rendering and visualized configuration. I hope it will help you. If you have any questions, please leave a message, the editor will reply to you in a timely manner. Thank you very much for your support for the help House website!