拒絕CV搬磚,如何優雅的使用elementUI的表單

有麼得前端小夥伴跟我有同樣的煩惱,每次寫表單就煩。這東西吧沒有任何難度,就是純體力活,項目中若是用了UI庫,那基本每次就是照着官網實例複製粘貼。假設項目是用的vue + elementUI,那常常會出現這種代碼javascript

<template>
    <div>
        <el-input 
            v-model="data1" 
            placeholder="請輸入內容"
            @change="onchange" />
        <el-input 
            v-model="data2" 
            type="textarea" 
            placeholder="請輸入內容"
            @change="onchange"/>
        <el-switch 
            v-model="data3"
            @change="onchange"/>
        <el-slider 
            v-model="data4"
            @change="onchange"/>
    </div>
</template>
data(){
    return{
        data1:0,
        data2:1,
        data3:2,
        data4:3,
    }
}
methods:{
    onchange(value){
        ........
    }
}

我這仍是寫的故意簡單一些,若是屬性和事件更多那這個頁面將來就頗有可能發展成咱們做爲程序眼最怕的事情。
老大:「小陳,XXX離職了,你接手一下XXX文件,不難就是有點亂,也就一萬多行吧」
我心裏:「尼瑪,明明幾行代碼加一個配置文件就搞定的事情,你可搖了我吧」html

開始重構之路
(本文以vue+elementUI爲例子,主要的是思想而不是代碼)前端

  1. 分析代碼,找出異同
    相同點:elementUI中每全部表單元素最外層都被<form>包裹,每一項都被<form-item>包裹,每一個具體的表單元素都是<el-XXX>形式的,每一個元素均可以經過value或者v-model來綁定數據。都具備一些公共的屬性和事件,好比change。除了select,別的元素均可以用一行寫完。
    不一樣點:每一個元素都有個性化的屬性與方法,好比<el-input>支持type屬性,<el-slider>支持max,min屬性。
  2. 設計思路,代碼實現
    用一個數組對象來表示表單,每一項是一個object,裏面包含了表單標籤全部用到的屬性,標籤名tag、綁定字段model、標題label。
    用一個對象來表示值,鍵值就是表單數組中聲明過的那些。vue

    // 表單數組
    let formList = [
        {
            tag: 'input',
            model: 'name',
            label: '姓名'
        },
        {
            tag: 'input-number',
            model: 'age',
            label: '年齡'
        },
        {
            tag: 'switch',
            model: 'working',
            label: '是否在職'
        },
    ]
    // 表單值
    let formData = {
        name: '小陳',
        age: 26,
        working: false,
    }

    數據的輸入輸出肯定後就須要肯定實現方式,能夠寫成一個vue組件,組件接受兩個props:[formList,formData],以後對formList進行遍歷,使用動態組件<component>來根據tag渲染出對應對標籤,v-mode傳入的model字段。再將label傳給<form-item>java

    <template>
        <el-form>
            <el-form-item 
                v-for="(item,index) in formList"
                :key="index"
                :label="item.label"
                >
                    <component 
                        v-model="formData[item.model]"
                        :is="`el-${item.tag}`" />
                </el-form-item>
        </form>
    </template>
  3. 解決差別,大功告成
    以前分析得出,最大的差別就是每一個元素都用不少個性化的屬性與事件,而且除了表單元素,<el-form>`<el-form-item>`也有不少屬性與事件,若是這些全都經過prop聲明,那可太多了,而且還很差區分誰是誰的。因此須要用到了vue的$attrs和$listeners,
    image.png

經過$attrs和$listeners批量綁定屬性與事件,同時修改formList數據格式爲git

let formList = [
    {
        tag: 'input',
        label: 'name',
        model: 'name',
        attrs: {
            // 個性化屬性
            type: 'textarea'
        },
        listeners: {
            // 個性化事件
            change:(value)=>console.log(value,'change'),
            blur:(value)=>console.log(value,'blur')
        }
    }
]
同時還要記得對select標籤單獨處理一下,最終代碼爲
```
<template>
  <el-form v-bind="$attrs">
    <template v-for="(item, index) in formList">
      <el-form-item
        :key="index"
        v-bind="item.formItem"
        v-if="item.tag === 'select'"
        :label="item.label"
      >
        <el-select v-model="formData[item.model]" v-on="item.listeners" v-bind="item.attrs">
          <el-option
            :value="option.value"
            :label="option.label"
            :key="idx"
            v-for="(option,idx) in item.options"
          ></el-option>
        </el-select>
      </el-form-item>
      <el-form-item v-else :key="index" v-bind="item.formItem" :label="item.label">
        <component
          v-model="formData[item.model]"
          v-on="item.listeners"
          v-bind="item.attrs"
          :is="`el-${item.tag}`"
        ></component>
      </el-form-item>
    </template>
  </el-form>
</template>

<script>
export default {
  props: {
    formList: {
      type: Array,
      required: true,
    },
    formData: {
      type: Object,
      default: () => ({}),
    },
  },
};
</script>

<style>
</style>
```
*注意:本例子默認elementUI全局註冊了哦*
  1. 效果
    效果
    代碼
相關文章
相關標籤/搜索