你不知道的Vue之 - ElementUI Table 二次封装(精简版)

1,098 阅读1分钟

需求

1.能像iview一样通过配置的方式传参数

2.能复用element-ui中table,el-table-column中的属性和事件

3.给table添加一些默认的属性

<custom-table :columns="columns" :data="data" height="500" border @selection-change="handleSelection" ... />

<script>
export default {
  data(){
    return {
      columns:[
        {label:'姓名', prop:'name', width:'60px', },
        {label:'地址', prop:'address'},
      ],
      data: [
        {name: '张三',address:'xxx'},
        {name: '李四',address:'xxx'},
      ]
    }  
  },
  methods:{
    handleSelection(val) {
      console.log(val);
    }
  }
}
</scirpt>

技术准备

1.怎么复用el-table的属性和事件呢?

在vue中attrsattrs listeners配合inheritAttrs 这俩个重要的api可以帮助我们最简单的实现属性和事件的在组件中传递

2.在遍历columns中会有很多判断条件,怎么实现多表头?

在这里可以使用jsx, 多表头可以用递归来处理。github.com/vuejs/jsx#i…

3.怎么实现slot header 和 slotScope呢?

可以在columns中使用传一个返回jsx的函数。

最终实现

<script>
export default {
  inheritAttrs: false,
  name: 'custom-table',
  props: {
    data: {
      type: Array,
    },
    columns: {
      type: Array,
    },
  },
  render() {
    function getTableColumn(data) {
      const excludeList = ['index', 'expand', 'selection'];
      const slots = {};
      if (data.headerRender) {
        slots.header = () => data.headerRender();
      }
      if (data.render) {
        slots.default = (scope) => data.render(scope);
      } else if (excludeList.indexOf(data.type) === -1) {
        slots.default = (scope) => scope.row[data.prop] || '--';
      }

      return (
        <el-table-column
          align="center"
          {...{ attrs: data }}
          scopedSlots={slots}>
          {
            data.children && data.children.map((i) => getTableColumn(i))
          }
        </el-table-column>
      );
    }
    const tableColumns = this.columns.map(getTableColumn);
    return (
      <el-table
        data={this.data}
        ref="table"
        tooltip-effect="dark"
        stripe
        border
        {...{ attrs: this.$attrs }}
        {...{ on: this.$listeners }}
      >
        {tableColumns}
      </el-table>);
  },
};
</script>

具体使用

<template>
  <div class="home">
    <el-button @click="handleClear">清理</el-button>
    <my-table
      :columns="columns"
      ref="table"
      @selection-change="handleSelect"
      @sort-change="handleSort"
      :data="data">
    </my-table>
  </div>
</template>
<script>

import MyTable from '@/components/my-table/index.vue';

export default {
  name: 'Home',
  components: {
    MyTable,
  },
  data() {
    return {
      columns: [
        { type: 'selection', width: '50px' },
        { type: 'index', width: '50px' },
        { prop: 'name', label: '姓名', align: 'right' },
        { prop: 'sex', label: '性别' },
        { prop: 'age', label: '年龄', align: 'right', sortable: true},
        {
          prop: 'info',
          label: '信息',
          children: [
            { prop: 'province', label: '省', align: 'left' },
            { prop: 'city', label: '市', align: 'right' },
          ],
        },
        {
          label: '操作',
          fixed: 'right',
          render: ({ row }) => [
            <el-button vOn:click={() => this.handleClick(row)}>按钮</el-button>,
            <el-button vOn:click={() => this.handleClick(row)}>编辑</el-button>,
          ],
        },
      ],
      data: [
        {
          name: '姓名', age: 1, sex: '男sddddddddddddad 单算打算多所所得到的多多多多多多多多多多多多多多多多多', city: '北京', province: '北京',
        },
        { name: '姓名1', age: 4 },
        { name: '姓名2', age: 3 },
        { name: '姓名2', age: 5 },
        { name: '姓名2', age: 6 },
        { name: '姓名2' },
        { name: '姓名2' },
      ],
    };
  },
  methods: {
    handleClick(row) {
      console.log(row);
    },
    handleSelect(data) {
      console.log(data);
    },
    handleClear() {
      console.log(this.$refs.table.$refs.table.clearSelection());
    },
    handleSort({ column, prop, order }) {
      console.log(column);
      console.log(prop);
      console.log(order);
    },
  },
};
</script>