国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁(yè) > 編程 > JavaScript > 正文

Vue+ElementUI實(shí)現(xiàn)表單動(dòng)態(tài)渲染、可視化配置的方法

2019-11-19 14:13:20
字體:
來(lái)源:轉(zhuǎn)載
供稿:網(wǎng)友

動(dòng)態(tài)渲染就是有一個(gè)異步的數(shù)據(jù),大概長(zhǎng)這樣:

{ "inline": true, "labelPosition": "right", "labelWidth": "", "size": "small", "statusIcon": true, "formItemList": [ { "type": "input", "label": "姓名", "disable": false, "readonly": false, "value": "", "placeholder": "請(qǐng)輸入姓名", "rules": [], "key": "name", "subtype": "text" }, { "type": "radio", "label": "性別", "value": "", "button": false, "border": true, "rules": [], "key": "gender", "options": [ {  "value": "1",  "label": "男",  "disabled": false }, {  "value": "0",  "label": "女",  "disabled": false } ] } ]}

然后你需要把這個(gè)json渲染成這樣:

 

最后提交表單的數(shù)據(jù)長(zhǎng)這樣:

{ "name": "Genji", "gender": "1"}

然后我們目標(biāo)就是封裝這樣一個(gè)組件:

<dynamic-form :config="someConfig" v-model="someData" />

實(shí)現(xiàn)

開(kāi)始之前,你需要知道 v-model 的工作原理 :

<input v-model="something">

這不過(guò)是以下示例的語(yǔ)法糖:

<input :value="something" @input="something = $event.target.value">

了解這些后,我們?cè)賮?lái)一步一步實(shí)現(xiàn)這個(gè)組件。

首先,把配置轉(zhuǎn)發(fā)到 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>

第二步,設(shè)置默認(rèn)值。

因?yàn)樵诿總€(gè) form-item 都會(huì)需要一個(gè) v-model ,所以在渲染之前,保證每個(gè)字段都有值。這里需要注意一點(diǎn),組件內(nèi)不要直接修改父組件傳入的 prop ,所以我們?cè)谶@里用 {...this.value} 快速拷貝一份,最后別忘了通知父組件。代碼如下:

export default { props: { formConfig: {...}, value: {...}, }, methods: { setDefaultValue() { const formData = { ...this.value } // 設(shè)置默認(rèn)值 this.formConfig.formItemList.forEach(({ key, value }) => { if (formData[key] === undefined || formData[key] === null) {  formData[key] = value } }) this.$emit('input', formData) } }, mounted() { this.setDefaultValue() },}

第三步,渲染 form-item 。

如何把下面的數(shù)據(jù)渲染為我們熟悉的 el-form-item ?

{ "type": "input", "label": "姓名", "disable": false, "readonly": false, "value": "", "placeholder": "請(qǐng)輸入姓名", "rules": [], "key": "name", "subtype": "text"}

第一種,利用 vue 內(nèi)置的 component 組件,寫(xiě)起來(lái)可能像這樣:

<el-form-item> <component :is="`el-${item.type}`" /></el-form-item>

第二種,使用 v-if 逐個(gè)判斷:

<el-form-item> <el-input v-if="item.type === 'input'" /> <span v-else>未知控件類(lèi)型</span></el-form-item>

考慮到每種表單控件的處理邏輯千差萬(wàn)別,樓主采用了第二種方式。

根據(jù)這個(gè)思路,我們來(lái)封裝一個(gè) dynamic-form-item ,接收一個(gè) item ,渲染一個(gè) 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> <!--突然有點(diǎn)想念JSX--> ... <span v-else>未知控件類(lèi)型</span> </el-form-item></template><script>export default { props: { item: { type: Object, required: true } }}</script>

tips: 使用 v-bind="$attrs" v-on="$listeners" 可以方便地轉(zhuǎn)發(fā)父組件的 v-model 指令,詳見(jiàn)vue高階組件。

最后,我們就可以循環(huán)輸出一個(gè)完整的表單了:

<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)" />

這里不能用 v-model="value[item.key]" ,上文說(shuō)了,組件內(nèi)不能直接修改props,所以這里我們還是轉(zhuǎn)發(fā)一下。

methods: { handleInput(val, key) { // 這里element-ui沒(méi)有上報(bào)event,直接就是value了 this.$emit('input', { ...this.value, [key]: val }) }, setDefaultValue() {...}},

完整代碼地址:  src/components/dynamic-form/form.vue

擴(kuò)展功能

1.數(shù)字顯示單位,限制小數(shù)位數(shù)

element-ui 沒(méi)有做這個(gè)功能,不過(guò)我覺(jué)得還是挺常見(jiàn)的,所以使用 el-input 手動(dòng)封裝了一個(gè) input-number :

 

<!--普通使用--><input-number  v-model="someNumber" :min="1"  :max="99"  :decimal1="2"  append="元"></input-number><!--在dynamic-form-item中的應(yīng)用--><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>

完整代碼: src/components/dynamic-form/input-number.vue

2.異步驗(yàn)證

得益于 async-validator ,我們可以很方便地自定義驗(yàn)證規(guī)則。

 

在配置中

{ "type": "input", ... "rules":[  {   "sql": "SELECT {key} FROM balabala",   "message": "xx已被占用",   "trigger": "blur"  } ]}

dynamic-form-item 組件中, 遍歷 item.rules , 將sql驗(yàn)證轉(zhuǎn)化為自定義 validator 函數(shù):

<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) => {   // 根據(jù)項(xiàng)目自行修改   request('/api/validate', 'POST', {    key: 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.省市區(qū)快捷配置

感謝 element-china-area-data 的作者。

在配置中:

{ "type": "cascader", ... "areaShortcut": "provinceAndCityData"}

在 dynamic-form-item 組件中:

<template> <el-form-item>  ...  <el-cascader    :options="item.options || require('element-china-area-data')[item.areaShortcut]"   ></el-cascader> </el-form-item></template>

4.從遠(yuǎn)程加載選項(xiàng)

包括但不限于 radio 、 checkbox 、 cascader 、 select

在配置中:

{ "type": "checkbox", ... "optionsUrl": "/api/some/options"}

在 dynamic-form-item 組件中:

<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) {  // 根據(jù)項(xiàng)目自行修改  request(`${optionsUrl}?key=${key}`, 'GET')  .then(res => {   this.ajaxOptions = res  })  .catch(err => { this.$message.error(err.message) }) } }}</script>

總結(jié)

以上所述是小編給大家介紹的Vue+ElementUI實(shí)現(xiàn)表單動(dòng)態(tài)渲染、可視化配置的方法,希望對(duì)大家有所幫助,如果大家有任何疑問(wèn)請(qǐng)給我留言,小編會(huì)及時(shí)回復(fù)大家的。在此也非常感謝大家對(duì)武林網(wǎng)網(wǎng)站的支持!

發(fā)表評(píng)論 共有條評(píng)論
用戶(hù)名: 密碼:
驗(yàn)證碼: 匿名發(fā)表
主站蜘蛛池模板: 三都| 高平市| 庐江县| 松江区| 弥勒县| 万源市| 栖霞市| 高雄市| 巫溪县| 内丘县| 噶尔县| 静乐县| 长乐市| 临朐县| 陈巴尔虎旗| 襄城县| 乌审旗| 叶城县| 林州市| 长泰县| 永靖县| 北流市| 新余市| 太康县| 双牌县| 乌苏市| 额济纳旗| 封开县| 茶陵县| 阿合奇县| 肇源县| 昌图县| 巴马| 贵德县| 和林格尔县| 谢通门县| 汉源县| 区。| 兴宁市| 潞西市| 肇源县|