让el-table更好用,通过配置的方式

3,277 阅读2分钟

element-ui虽然有el-table组件,但是仍然需要手动写el-table-column

e-el-table1

这里希望进一步抽离配置,在 el-table的基础上封装个enhanced-el-table组件。

使用的时候希望这样,不再需要手动写里面的el-table-column

<enhanced-el-table :data="tableData" :colConfigs="colConfigs" ></enhanced-el-table>
  • data属性,显示的数据,[{name:'颜酱',age:18},{...}]
  • colConfigs属性,每个column项的配置数组,如下
colConfigs: [
    { prop: "date", label: "日期"},
    { prop: "name", label: "姓名"},
    { prop: 'address', label: '地址'}
]

可以结合表格看colConfigs就更容易理解了,其实就是将el-table-column上的属性换成对象的形式

e-el-table2

本文代码后期可能较复杂,需要的话,可以去看github代码

当然文末也附上了,每个小节的具体代码,有需要也可以看看

TL;DR

  • 就是写了个enhanced-el-table组件,充当原先的el-table组件
  • 唯一不一样的是,额外加了一个colConfigs,其他属性、事件、方法同el-table组件
  • 哦,如果表格的列项不足以用colConfigs描述的话,这边提供了slot
  • 想直接看enhanced-el-table组件怎么用的,包括复杂情况,直接跳到本文的演示实例的优化

组件的概况

综上,enhanced-el-table组件的大概就出来了。

e-el-table9

el-table-column的处理

实现最开始的表格:

App.vue里可以简单写下:

e-el-table5

enhanced-el-table内部,没有colConfigs的情况下,长这样

el-table(:data="data")
  el-table-column(label="日期" prop="date")
  el-table-column(label="姓名" prop="name")
  el-table-column(label="地址" prop="address")

当然,有了colConfigs,直接就循环了

el-table(:data="data")
  el-table-column(v-for="config in colConfigs"  v-bind="config" :key="config.prop")

优化

  • el-table自身也有很多属性,这里通过简单的v-bind="$attrs",将enhanced-el-from上面的属性自动到el-table
  • 同理,v-on="$listeners"
  • el-table上面的方法,稍微麻烦点,通过手动赋值
  • 部分列项,需要定制,通过slotName属性,表示不参与内部循环,需要自己写逻辑
  • 经评论区 @白人酋长 提醒,多层表头的情况,这边直接用children处理,目前只写了两层逻辑,更多层的话最好使用递归,递归组件怎么写
//   el-table(ref="elTable":data="data" v-bind="$attrs" v-on="$listeners")
  mounted() {
    const methods = [ "clearSelection", "toggleRowSelection", "toggleAllSelection", "toggleRowExpansion", "setCurrentRow", "clearSort", "clearFilter", "doLayout", "sort" ];
    methods.forEach(method => (this[method] = this.$refs.elTable[method]));
  }

以上逻辑将在下面的部分展示全部代码。

演示实例的优化

实例的效果:

e-el-table8

EnhancedElTable的代码如下

<template lang="pug">
  el-table(ref="elTable" :data="data" v-bind="$attrs" v-on="$listeners")
    template(v-for="colConfig in colConfigs")
      slot(v-if="colConfig.slotName" :name="colConfig.slotName" v-bind="colConfig")
      //- 这边目前只写了两个层级,更多层级可能需要递归,请参考https://juejin.cn/post/6868560126602412045
      el-table-column(v-else-if="colConfig.children && colConfig.children.length" v-bind="colConfig" :key="colConfig.label")
        el-table-column(v-for="innerColConfig in colConfig.children" v-bind="innerColConfig" :key="innerColConfig.label")
      el-table-column(v-else="colConfig.children && colConfig.children.length" v-bind="colConfig" :key="colConfig.label")
</template>

<script>
export default {
  name: "enhanced-el-table",
  props: {
    data: {
      type: Array,
      default() {
        return [];
      }
    },
    colConfigs: {
      type: Array,
      default() {
        return [];
      }
    }
  },
  mounted() {
    const methods = [ "clearSelection", "toggleRowSelection", "toggleAllSelection", "toggleRowExpansion", "setCurrentRow", "clearSort", "clearFilter", "doLayout", "sort" ];
    methods.forEach(method => (this[method] = this.$refs.elTable[method]));
  }
};
</script>


App.vue的代码如下

<template lang="pug">
div#app
  enhanced-el-table(:data="tableData",:colConfigs="colConfigs" ref="multipleTable" tooltip-effect="dark" style="width: 100%" @selection-change="handleSelectionChange")
    //- 这里的action 需要自定制列
    template(#action="colConfig")
      el-table-column(v-bind="colConfig")
        template(#default="scope")
          el-button(size="mini" @click="handleEdit(scope.$index, scope.row)") 编辑
          el-button(type="danger" size="mini" @click="handleDelete(scope.$index, scope.row)") 删除
  div(style="margin-top: 20px")
    el-button(@click="toggleSelection([tableData[1], tableData[2]])") 切换第二、第三行的选中状态
    el-button(@click="toggleSelection()") 取消选择
  div {{multipleSelection}}
</template>

<script>
import EnhancedElTable from "./components/EnhancedElTable.vue";
export default {
  name: "App",
  components: {
    EnhancedElTable
  },
  data() {
    return {
      colConfigs: [
        { type: "selection", width: 55 },
        { prop: "date", label: "日期", width: 180 },
        { prop: "name", label: "姓名", width: 180, sortable: true },
        {
          label: "地址",
          children: [
            { prop: "province", label: "省" },
            { prop: "city", label: "市" },
            { prop: "address", label: "地址" }
          ]
        },
        // 这里的action 需要自定制列
        { slotName: "action", label: "操作" }
      ],

      tableData: Array.from({ length: 6 }, (v, i) => ({
        date: `2016-5-${i + 1}`,
        name: `王小虎${i + 1}`,
        province: `省${i + 1} `,
        city: `市${i + 1} `,
        address: `上海市普陀区金沙江路 151${i + 1} 弄`
      })),

      multipleSelection: []
    };
  },
  methods: {
    toggleSelection(rows) {
      if (rows) {
        rows.forEach(row => {
          this.$refs.multipleTable.toggleRowSelection(row);
        });
      } else {
        this.$refs.multipleTable.clearSelection();
      }
    },
    handleSelectionChange(val) {
      this.multipleSelection = val;
    },
    handleEdit(index, row) {
      console.log(index, row);
    },
    handleDelete(index, row) {
      console.log(index, row);
    }
  }
};
</script>

<style>
#app {
  font-family: Avenir, Helvetica, Arial, sans-serif;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  color: #2c3e50;
}
</style>

引用

对了,还有个姊妹篇,让el-form更好用,通过配置的方式

代码

代码:组件的概况

<template lang="pug">
  el-table(:data="data")
</template>

<script>
export default {
  name: "enhanced-el-table",
  props: {
    data: {
      type: Array,
      default() {
        return [];
      }
    },
    colConfigs: {
      type: Array,
      default() {
        return [];
      }
    }
  }
};
</script>