改造element-table,使其能拖拽表头并且排序

2,712 阅读1分钟

自己改造element-table

element的table组件封装很完善了,但遇到特殊需求却无能为力。 项目需要表头可以拖拽,于是想到element使用插槽可以自定义header,由此可以操控它!

1. 项目结构

vue的项目(肯定要装element的插件啦),template模板如下所示

<template>
  <div class="table-container">
    <el-table
      :data="tableData"
      height="250"
      border
      style="width: 100%"
    >
      <el-table-column
        :key="h.prop"
        v-for="h in tableHeaders"
        :prop="h.prop"
        :label="h.label"
        header-align="center"
        sortable
        draggable="true"
      >
        <template slot="header" slot-scope="{ column }">
          <span class="header-label" :id="h.prop">{{ column.label }}</span>
        </template>
      </el-table-column>
    </el-table>
  </div>
</template>

script 部分如下所示,因为是改造element自己的组件。所以使用常规的vue @事件监听就不现实了,所以咱们自己用原生的js来实现(jquery也可以,一切操作dom的库都行,我个人偷懒就直接用原生了)

<script>
export default {
  name: "HelloWorld",
  methods: {
    handleSortClick(e, column) {},
    setCells() {
      setTimeout(() => {
        let cells = document.querySelectorAll(".has-gutter th .cell");
        cells.forEach((cell, index) => {
          cell.index = index;
          cell.draggable = true;
          cell.addEventListener("dragover", (e) => {
            e.preventDefault();
          });
          cell.addEventListener("dragleave", (e) => {
            e.target.style.border = "none";
          });
          cell.addEventListener("drop", (e) => {
            e.preventDefault();
            let cell = e.path.find((p) => p.className === "cell");
            if (!cell) {
              return;
            }
            cell.style.border = "none";
            if (this.target !== cell) {
              let prop1 = this.target.children[0].id;
              let prop2 = cell.children[0].id;
              let index1 = this.tableHeaders.findIndex((h) => h.prop === prop1);
              let index2 = this.tableHeaders.findIndex((h) => h.prop === prop2);

              let temp = this.tableHeaders[index1];
              this.tableHeaders[index1] = this.tableHeaders[index2];
              this.tableHeaders[index2] = temp;
            }
            this.setCells();
            this.kd = Date.now();
          });
          cell.addEventListener("dragenter", (e) => {
            let cell = e.path.find((p) => p.className === "cell");
            if (!cell) {
              return;
            }
            if (this.target !== cell) {
              setTimeout(() => {
                if (this.target.index > cell.index) {
                  cell.style.borderLeft = "1px solid red";
                } else {
                  cell.style.borderRight = "1px solid red";
                }
              }, 0);
            }
          });
          cell.addEventListener("dragstart", (e) => {
            // 如果是拖拽宽度就不触发
            if (document.body.style.cursor === "col-resize") {
              this.target = {};
              return;
            }
            setTimeout(() => {
              e.stopPropagation();
              if (this.target.toString() === "{}") {
                cell.style.backgroundColor = "#eee";
              }
              this.target = e.target;
            }, 0);
          });
          cell.addEventListener("dragend", (e) => {
            cell.style.backgroundColor = "#fff";
            e.target.style.border = "none";
          });
          cell.addEventListener("mousedown", (e) => {});
        });
      }, 0);
    },
    contextmenu(column, event) {
      event.preventDefault();
      console.log(column, event);
      let prop = column.property;
      // let index = this.tableHeaders.findIndex(h=>h.prop===prop)
      // this.tableHeaders.splice(index,1)
    },
  },
  mounted() {
    this.setCells();
  },
  data() {
    return {
      target: {},
      sortIndex: "0",
      kd: Date.now(),
      tableHeaders: [
        { prop: "date", label: "日期" },
        { prop: "name", label: "姓名" },
        { prop: "address", label: "地址" },
      ],
      tableData: [
        {
          date: "2016-05-03",
          name: "王小虎",
          address: "上海市普陀区金沙江路 1518 弄",
        },
        {
          date: "2016-05-02",
          name: "王小虎",
          address: "上海市普陀区金沙江路 1518 弄",
        },
        {
          date: "2016-05-04",
          name: "王小虎",
          address: "上海市普陀区金沙江路 1518 弄",
        },
        {
          date: "2016-05-01",
          name: "王小虎",
          address: "上海市普陀区金沙江路 1518 弄",
        },
        {
          date: "2016-05-08",
          name: "王小虎",
          address: "上海市普陀区金沙江路 1518 弄",
        },
        {
          date: "2016-05-06",
          name: "王小虎",
          address: "上海市普陀区金沙江路 1518 弄",
        },
        {
          date: "2016-05-07",
          name: "王小虎",
          address: "上海市普陀区金沙江路 1518 弄",
        },
      ],
    };
  },
};
</script>

下面是css部分,涉及到修改element的样式,所以需要/deep/,我是用的scss预处理器,若需要css请自行更改

<style lang="scss" scoped>
.table-container {
  padding: 20px;
  display: flex;
  align-items: center;
  justify-content: center;
  .header-label {
    padding: 10px 20px;
  }
}
/deep/ .el-table th > .cell {
  padding: 0;
}
/deep/ .el-table th {
  padding: 0;
}
</style>

2.效果

动画.gif