vue動(dòng)態(tài)渲染表單配置項(xiàng)

vue動(dòng)態(tài)渲染表單配置項(xiàng)

在項(xiàng)目中,我們經(jīng)常會(huì)用到各種表單,但是數(shù)量一般都不多持际,那當(dāng)我們編寫大量表單時(shí)怎么辦呢,難道我們還要一個(gè)標(biāo)簽一個(gè)標(biāo)簽的寫嗎哗咆?如果各個(gè)表單之間又出現(xiàn)了各種級(jí)聯(lián)關(guān)系各種判斷呢蜘欲?所以這時(shí)候就出現(xiàn)了另外一種方式,我們可以通過(guò)對(duì)象的方式編寫表單項(xiàng)來(lái)替換element本來(lái)的標(biāo)簽寫法晌柬,以使我們能夠方便清晰的最大化的控制每個(gè)表單姥份。

當(dāng)我們編寫一個(gè)普通的input表單時(shí)郭脂,我們一般會(huì)直接在template里這樣寫:

<el-input v-model="inputValue" placeholder="請(qǐng)輸入"></el-input>

用了表單配置項(xiàng)后,我們可以這樣在data里寫:

{
  type: 'input',
  key: 'inputValue',
  label: 'input框:',
  placeholder: '請(qǐng)輸入'
}

我們先不討論怎么就可以這樣寫了澈歉,我們先來(lái)明白為什么要這樣用

  • 可以通過(guò)this.XXX來(lái)改變某個(gè)表單項(xiàng)
  • 不用再在標(biāo)簽里加各種判斷
  • 標(biāo)簽寫法太死板
  • render寫法展鸡,更貼近vue底層

如何配置

input舉栗,最后會(huì)附上其他的表單項(xiàng)

// 準(zhǔn)備一個(gè)文件---itemRenders.js
export default {
  name: 'ItemRender',
  props: {
    // 類型埃难,input or select or ...
    type: String,
    // 主要配置項(xiàng)
    config: Object
  },
  // 渲染函數(shù)
  render: function (h) {
    switch (this.type) {
      case 'input':
        return inputItem(h, this.config);
      default:
        return '';
    }
  }
};  

function inputItem(h, config) {
  let {
    key, // 綁定的值
    props, // 屬性, 如disable等
    listeners, // 事件莹弊,如onblur等
    placeholder,
    areaProps // 額外屬性如type等
  } = config;
  let on = listeners || {};
  let pps = props || {};
  let area = areaProps || {};
  return h('el-input', {
    props: {
      ...pps,
      value: key,
      disabled: pps.disabled
    },
    attrs: {
      placeholder: placeholder || pps.placeholder || '請(qǐng)輸入',
      ...area
    },
    on: {
      ...on,
      // 實(shí)現(xiàn)雙向綁定
      input: (val) => {
        key = val;
      }
    }
  });
}

如何使用

在.vue文件中使用itemRenders.js

<template>
    <div>
        <item-render
          :type="item.type"
          :config="{
            placeholder: item.placeholder || '',
            ...item.config,
            key: item.key
          }"
        >
        </item-render>
    </div>
</template>

<script>
    import ItemRender from './itemRenders';
    export default {
        components: { 'item-render': ItemRender },
        data() {
            return {
                item: {
                    type: 'input',
                     key: 'inputValue',
                     label: 'input框:',
                     placeholder: '請(qǐng)輸入',
                     config: {
                        props: {
                          disabled: true
                        },
                        listeners: {
                          blur: _this.blur1
                        }
                     }
                }
            }
        }
    }
</script>

這只是渲染一個(gè)input的寫法,但既然會(huì)用到這種寫法涡尘,那就代表要渲染的表單數(shù)量可能有點(diǎn)大忍弛,像我們項(xiàng)目中有些頁(yè)面新增時(shí)表單項(xiàng)多達(dá)100+,所以悟衩,如果頁(yè)面只用到個(gè)位數(shù)的表單的情況剧罩,這里還是建議親親直接使用ele提供的標(biāo)簽寫法。

渲染大量表單

那渲染大量表單時(shí)要怎么配置呢座泳?

其實(shí)也很簡(jiǎn)單惠昔,套個(gè)form就行了(主要以提交form表單為主)

我們可以先來(lái)準(zhǔn)備個(gè)form表單組件,用的時(shí)候只需引入該組件即可

// formRender.vue
<template>
  <el-form
    ref="formRender"
    :model="model"
    :rules="rules"
  >
    <div class="block">
      <el-form-item
        v-for="item in items"
        :key="item.key"
        :label="item.label"
        :prop="item.key"
      >
        <item-render
          :type="item.type"
          :config="{
            placeholder: item.placeholder || '',
            ...item.config,
            model,
            key: item.key
          }"
        >
        </item-render>
      </el-form-item>
    </div>
  </el-form>
</template>
<script>
    import ItemRender from './itemRenders';
    export default {
        components: { 'item-render': ItemRender },
        props: {
            model: {
              type: Object,
              default: () => {}
            },
            // 規(guī)則
            rules: {
              type: Object,
              default: () => {}
            },
            items: {
              type: Array,
              default: () => []
            }
        },
    }
</script>

項(xiàng)目中使用

<template>
    <FormRender
        ref="formRender"
        :model="form"
        :rules="basicRules"
        :items="items1"
      ></FormRender>
</template>
<script>
    import FormRender from './formRender';
    export default {
        components: {FormRender},
        data() {
            return {
                form: {
                    formItem1: '',
                    formItem2: [],
                    formItem3: ''
                },
                items1: [
                    // 輸入框
                    {
                        type: 'input',
                        key: 'formItem1',
                        label: 'formItem1:',
                        placeholder: '請(qǐng)輸入',
                    }挑势,
                    // 下拉框
                    {
                        type: 'select',
                        key: 'formItem2',
                        label: 'formItem2:',
                        placeholder: '請(qǐng)選擇',
                        config: {
                            props: {
                              filterable: true,
                              clearable: true,
                              disabled: false
                            },
                            options: () => _this.formItem2s,
                            optionConfig: {
                              label: 'name',
                              value: 'code'
                            },
                            listeners: {
                              change: _this.handleChange
                            }
                      }
                    }
                ],
                basicRules: {
                    formItem1: [ { required: true, trigger: 'blur' }]
                },
                formItem2s: []
            }
         }
    }
</script>

其余表單配置項(xiàng)

這里只提供部分常用的給大家做參考镇防,大家也可以從別的角度去考慮,適合我們的并不一定適合所有人

  • 下拉選擇框

    function selectItem(h, config) {
    let {
      model,
      key,
      props,
      listeners,
      options,
      optionConfig,
      placeholder,
      syncConfig
    } = config;
    
    let opl = 'label';
    let opv = 'value';
    if (optionConfig) {
      if (optionConfig.label) {
        opl = optionConfig.label;
      }
      if (optionConfig.value) {
        opv = optionConfig.value;
      }
    }
    
    let opts = options();
    let ops = [];
    if (opts) {
      ops = opts.map((option) => {
        return h('el-option', {
          key: option[opv],
          props: {
            label: option[opl] || option['text'],
            value: option[opv],
            disabled: option.disabled
          }
        });
      });
    }
    
    let on = listeners || {};
    let pps = props || {};
    if (syncConfig) {
      pps = {
        ...pps,
        ...syncConfig()
      };
    }
    
    return h(
      'el-select', {
        props: {
          placeholder,
          ...pps,
          value: model[key]
        },
        on: {
          ...on,
          change: (val) => {
            model[key] = val;
            if (on.change) {
              on.change(val);
            }
          }
        }
      },
      ops
    );
    }
    
  • 日期選擇器

    function dateItem(h, config) {
      let {
        model,
        key,
        props,
        listeners,
        placeholder,
        type
      } = config;
      let pps = props || {};
      let on = listeners || {};
      return h('el-date-picker', {
        props: {
          ...pps,
          value: model[key]
        },
        attrs: {
          placeholder: placeholder || pps.placeholder || '請(qǐng)輸入',
          type: type || 'date'
        },
        on: {
          ...on,
          input: (val) => {
            model[key] = val;
          }
        }
      });
    }
    
  • 計(jì)數(shù)器

    function inputNumberItem(h, config) {
      let {
        model,
        key,
        props
      } = config;
      let pps = props || {};
      return h('el-input-number', {
        props: {
          ...pps,
          value: model[key]
        },
        on: {
          change: (val) => {
            model[key] = val;
          }
        }
      });
    }
    
  • 上傳

    function uploadItem(h, config) {
      let {
        model,
        key,
        props,
        btnProps,
        listeners,
        iconProps
      } = config;
      let pps = props || {};
      let btnProp = btnProps || {};
      let iconProp = iconProps || {};
      let on = listeners || {};
      return h(
        'el-upload', {
          props: {
            ...pps,
            'file-list': model[key]
          },
          class: {
            upload_demo: true
          },
          on: {
            ...on
          }
        },
        [
          h(
            'el-button', {
              props: {
                ...btnProp,
                size: btnProp.size || 'small'
              }
            },
            [
              h('svg-icon', {
                style: iconProp.styles,
                props: {
                  iconClass: iconProp.iconClass
                }
              }),
              '上傳'
            ]
          )
        ]
      );
    }
    
  • 級(jí)聯(lián)選擇器

    function cascaderItem(h, config) {
      let {
        model,
        key,
        props,
        listeners,
        options,
        optionProps
      } = config;
      let ops = options();
      let on = listeners || {};
      let pps = props || {};
      return h('el-cascader', {
        props: {
          value: model[key],
          ...pps,
          options: ops,
          props: optionProps
        },
        on: {
          change: (val) => {
            model[key] = val;
            if (on.change) {
              on.change(val);
            }
          }
        }
      });
    }
    
  • 時(shí)間選擇器

    function timePicker(h, config) {
      let {
        model,
        key,
        props,
        listeners,
        placeholder,
        type,
        syncConfig
      } = config;
      let pps = props || {};
      if (syncConfig) {
        pps = {
          ...pps,
          ...syncConfig()
        };
      }
      let on = listeners || {};
      return h('el-time-picker', {
        props: {
          ...pps,
          value: model[key]
        },
        attrs: {
          placeholder: placeholder || pps.placeholder || '請(qǐng)輸入',
          type: type || 'date'
        },
        on: {
          ...on,
          input: (val) => {
            model[key] = val;
          }
        }
      });
    }
    
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末潮饱,一起剝皮案震驚了整個(gè)濱河市来氧,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌香拉,老刑警劉巖啦扬,帶你破解...
    沈念sama閱讀 221,820評(píng)論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異凫碌,居然都是意外死亡扑毡,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,648評(píng)論 3 399
  • 文/潘曉璐 我一進(jìn)店門盛险,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)瞄摊,“玉大人,你說(shuō)我怎么就攤上這事苦掘』恢模” “怎么了?”我有些...
    開封第一講書人閱讀 168,324評(píng)論 0 360
  • 文/不壞的土叔 我叫張陵鹤啡,是天一觀的道長(zhǎng)惯驼。 經(jīng)常有香客問(wèn)我,道長(zhǎng)揉忘,這世上最難降的妖魔是什么跳座? 我笑而不...
    開封第一講書人閱讀 59,714評(píng)論 1 297
  • 正文 為了忘掉前任端铛,我火速辦了婚禮,結(jié)果婚禮上疲眷,老公的妹妹穿的比我還像新娘禾蚕。我一直安慰自己,他們只是感情好狂丝,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,724評(píng)論 6 397
  • 文/花漫 我一把揭開白布换淆。 她就那樣靜靜地躺著,像睡著了一般几颜。 火紅的嫁衣襯著肌膚如雪倍试。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 52,328評(píng)論 1 310
  • 那天蛋哭,我揣著相機(jī)與錄音县习,去河邊找鬼。 笑死谆趾,一個(gè)胖子當(dāng)著我的面吹牛躁愿,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播沪蓬,決...
    沈念sama閱讀 40,897評(píng)論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼彤钟,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了跷叉?” 一聲冷哼從身側(cè)響起逸雹,我...
    開封第一講書人閱讀 39,804評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎云挟,沒(méi)想到半個(gè)月后梆砸,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 46,345評(píng)論 1 318
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡园欣,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,431評(píng)論 3 340
  • 正文 我和宋清朗相戀三年辫樱,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片俊庇。...
    茶點(diǎn)故事閱讀 40,561評(píng)論 1 352
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖鸡挠,靈堂內(nèi)的尸體忽然破棺而出辉饱,到底是詐尸還是另有隱情,我是刑警寧澤拣展,帶...
    沈念sama閱讀 36,238評(píng)論 5 350
  • 正文 年R本政府宣布彭沼,位于F島的核電站,受9級(jí)特大地震影響备埃,放射性物質(zhì)發(fā)生泄漏姓惑。R本人自食惡果不足惜褐奴,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,928評(píng)論 3 334
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望于毙。 院中可真熱鬧敦冬,春花似錦、人聲如沸唯沮。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,417評(píng)論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)介蛉。三九已至萌庆,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間币旧,已是汗流浹背践险。 一陣腳步聲響...
    開封第一講書人閱讀 33,528評(píng)論 1 272
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留吹菱,地道東北人巍虫。 一個(gè)月前我還...
    沈念sama閱讀 48,983評(píng)論 3 376
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像毁葱,于是被迫代替她去往敵國(guó)和親垫言。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,573評(píng)論 2 359

推薦閱讀更多精彩內(nèi)容

  • mean to add the formatted="false" attribute?.[ 46% 47325/...
    ProZoom閱讀 2,701評(píng)論 0 3
  • Vue 實(shí)例 屬性和方法 每個(gè) Vue 實(shí)例都會(huì)代理其 data 對(duì)象里所有的屬性:var data = { a:...
    云之外閱讀 2,221評(píng)論 0 6
  • 以下內(nèi)容是我在學(xué)習(xí)和研究Vue時(shí)倾剿,對(duì)Vue的特性筷频、重點(diǎn)和注意事項(xiàng)的提取、精練和總結(jié)前痘,可以做為Vue特性的字典凛捏; 1...
    科研者閱讀 14,094評(píng)論 3 24
  • "use strict";function _classCallCheck(e,t){if(!(e instanc...
    久些閱讀 2,034評(píng)論 0 2
  • 看過(guò)很多相似的場(chǎng)景,一個(gè)孩子吃著飯突然從碗底翻出一個(gè)荷包蛋或者一個(gè)黃燦燦的太陽(yáng)蛋芹缔,母親在一旁慈愛(ài)地看著他坯癣,“海底撈...
    飛飛的碎碎念閱讀 1,204評(píng)論 28 36