如何避免重複性地做資料維護頁面?

Codeeeee發表於2018-12-15

作為一枚做後臺管理系統的前端,除了羨慕做移動端或小程式的同行,就是經常被要求做一個XX的維護頁面! 這不,這周PO又說:小X啊,給系統做個手機號歸屬地的維護頁面吧!

什麼是維護頁面?就是無聊透頂的增刪改查頁面唄! 反正有現成的UI框架,然後就是對著文件寫一些自定義標籤、配置下屬性、通過後端給的介面獲取資料填充上...

因此,基本的維護頁面元件大致是這個樣子:

<template>
  <div>
    <el-table :data="tableData">
      <el-table-column prop="key1" label="value2"></el-table-column>
      <el-table-column prop="key2" label="value2"></el-table-column>
      ...
      <el-table-column label="操作">
        <template slot-scope="scope">
          <el-button @click="handleEdit">編輯</el-button>
          <el-button @click="handleDel">刪除</el-button>
        </template>
      </el-table-column>
  </div>
</template>
複製程式碼

最終呈現的頁面:

image.png

但是,這次終於爆發了,不想再做這種重複性工作了!(當然不是拒絕不做) 想著,要是通過配置JSON,直接生成頁面就好了! 尋思著,對Element-UI的Tabel元件再做一層封裝! 最終,只要配置以下JSON引數,就可以自動生成需要的頁面:

const options = {
  table: {
    columns: [
      {
        prop: 'value1',
        label: 'key1'
      },
      {
        prop: 'value2',
        label: 'key2'
      }
    ],
    handle: getData
  }
};
複製程式碼

這是最基本的配置,但Element-UI的Table元件本身還支援很多配置引數,這些配置若也在JSON中,也要正常作用。因此,template模板寫法並不適用,或者說自由度不高,所以採用了JSX的寫法:

export default {
  props: {
    options: Object
  },
  
  data() {
    return {
      tableData: []
    };
  };

  render(h) {
    const tpl = <div></div>;
    const tableTpl = <el-table data={ this.tableData }></el-table>;
    const options = this.options;
    const componentOptions = tableTpl.componentOptions;
  
    // 遍歷傳入的屬性,配置在原生的Element Table元件上
     (let option in options.table) {
      componentOptions.propsData[option] = options.table[option];
    }
  
    options.table.columns.forEach(column => {
      const columnTpl = <column options={ column }></column>;
      componentOptions.children.push(columnTpl);
    });

    tpl.children.push(tableTpl);

    return tpl;
  },

  methods: {
    getData() {
      const options = this.options;
      const params = {};
      
      options.handle && options.handle(params).then(res => {
        if (res.status === 0) {
          this.tableData = res.result.Body;
        }
      });
    }
  },

  created() {
    this.getData();
  }
}
複製程式碼

根元素用div,而不直接用el-table,是方便為了以後加入分頁與表單篩選。

其實,表格的最後一列,雖然作為維護頁面基本就是編輯與刪除,但也不保證沒有變動!需求這種東西誰知道呢。因此,將最後一列的內容與邏輯都丟擲來,不放在元件裡實現,但要保證其擁有原先的作用域。這裡,就需要藉助vue的作用域插槽,比如我們是這麼使用元件的:

<custom-table :options="options">
  <template slot-scope="scope">
    <el-button size="small" type="text" @click="handleClick(scope)">編輯</el-button>
  </template>
</custom-table>
複製程式碼

這裡的點選事件處理方法的引數scope,就是原生el-table-column元件的作用域,即 scope = { row, column, $index }。 因此,需要對el-table-column也做一層封裝:

components: {
  Column: {
    props: {
      options: Object
    },

  render(h) {
    const tpl = <el-table-column ></el-table-column>;
    const options = this.options;
    const componentOptions = tpl.componentOptions;
                
    for (let option in options) {
      if (option === 'slot') {
        const slot = this.$parent.$parent.$scopedSlots.default;
                        
        tpl.data['scopedSlots'] = {
          default: scope => {
            return [slot(scope)];
          }
        };
      }
      else {
        componentOptions.propsData[option] = options[option];
      }
  }
                
  return tpl;
  }
}
複製程式碼

這裡要注意,獲取的slot是一個函式,需要執行再傳入。

到這裡,其實只是滿足了最最基本的資料展示,還有許多功能並未實現,比如資料行的選擇之類的。之後的實現會加入分頁與表單!

若有寫的不好的地方,歡迎指出!

相關文章