ant-desing-vue table 可伸缩列多级表头可拖动解决方案

<template>
<a-card>
  <a-table
    :columns="columns"
    :components="drag(columns)"
    :data-source="data"
    :size="attrBute.cellsize"
    bordered
    :rowKey="(record, index) => index"
    :pagination="attrBute.pagination"
    class="table"
  >
  </a-table>
  </a-card>
</template>

<script>
import Vue from "vue";
import VueDraggableResizable from "vue-draggable-resizable";
Vue.component("vue-draggable-resizable", VueDraggableResizable);

export default {
  data() {
    return {
      columns: [
        {
          title: "基本信息",
          children: [
            {
              title: "大学",
              dataIndex: "name",
              key: "name",
              width: 100,
            },
            {
              title: "年龄",
              dataIndex: "age",
              key: "age",
              width: 100,
            },
          ],
        },
        {
          title: "学校信息",
          children: [
            {
              title: "大学",
              dataIndex: "daxue",
              key: "daxue",
              width: 100,
            },
            {
              title: "学历",
              dataIndex: "xueli",
              key: "xueli",
              width: 100,
            },
          ],
        },
        {
          title: "户籍",
          dataIndex: "huji",
          width: 300,
        },
      ],
      data: [
        {
          name: "张三",
          age: "18",
          daxue: "长江大学",
          xueli: "研究生",
          huji: "湖北襄阳",
        },
      ],
      maxLevel: 1,
      cellsize: "small",
      attrBute: {
        bordered: false,
        pagination: false,
        isIndex: false, // index 序列
        isCheck: false, // 是否有复选框
        isTree: false,
        cellsize: "small",
      },
    };
  },
  methods: {
    drag(columns) {
      return {
        header: {
          cell: this.initDrag(columns),
        },
      };
    },
    /**
     * @param { 表格columns } tbCols
     */
    initDrag(tbCols) {
      let draggingMap = {};
      this.getDraggingMap(tbCols, draggingMap, 1);
      let draggingState = Vue.observable(draggingMap);
      return (h, props, children) => {
        let thDomIndex = 0;
        const { key, ...restProps } = props;
        let col = {};
        // 处理多级表头
        col = this.getRenderCoL(key, tbCols);
        if (!col || !col.width) {
          //这儿要求表格数据中要有宽width属性,若是没有是不会执行下面的拖拽的
          return <th {...restProps}>{children}</th>;
        }
        const onDrag = (x) => {
          col.width = Math.max(x, 1);
          draggingState[key] = col.width;
          thDomIndex = 0;
          loopDom(tbCols, col);
          // 自带复选框 列
          if (!this.attrBute.isCheck) {
            thDomIndex--;
          }
          let colgroup = document.querySelectorAll("colgroup");
          colgroup.forEach((Element) => {
            let childCol = Element.children;
            if (childCol[thDomIndex])
              childCol[thDomIndex].style.width = col.width + "px";
          });
          // 固定列情况,resetFixedColumns中的参数 width 要经过计算得到整个变化后的table-fixed-left的宽度
          if (col.fixed)
            this.resetFixedColumns(col.width + this.attrBute.isCheck ? 60 : 0);
        };
        const loopDom = (cols, col) => {
          let tag = true;
          this._.forEach(cols, (co) => {
            if (co.dataIndex == col.dataIndex) {
              thDomIndex++;
              tag = false;
              return tag;
            }
            if (co.children) {
              tag = loopDom(co.children, col);
              return tag;
            } else {
              thDomIndex++;
            }
          });
          return tag;
        };
        const onDragstop = () => {};
        let helper;
        if (col.helper) {
          helper = <span>{this.$slots[col.dataIndex + "_helper"]}</span>;
        }
        return (
          <th
            {...restProps}
            width={draggingState[key]}
            class="resize-table-th"
            dataIndex={col.key}
          >
            {children}
            {helper}
            <vue-draggable-resizable
              key={col.dataIndex || col.key}
              class="table-draggable-handle"
              w={20}
              h={this.getResizableHandler(col)}
              x={draggingState[key]}
              z={100}
              axis="x"
              draggable={true}
              resizable={false}
              onDragging={onDrag}
              onDragstop={onDragstop}
            ></vue-draggable-resizable>
          </th>
        );
      };
    },
    getheadT(d) {
      return d.newTitle;
    },
    getheadTis(d) {
      return d.tips;
    },
    getResizableHandler(col) {
      // let baseH = thDom.getBoundingClientRect().height;
      // 单元格size
      let size = this.cellsize ? this.cellsize : this.attrBute.cellsize;
      let baseH = size == "middle" ? 47 : size == "small" ? 39 : 55;
      if (col.isEndNode) return baseH * col.nodeLevel;
      else if (col.leafNode && col.nodeLevel < this.maxLevel) {
        return baseH * this.maxLevel;
      } else return baseH;
    },
    resetFixedColumns(width) {
      const fixedHead = document.querySelector(
        ".ant-table-fixed-left .ant-table-header"
      );
      const fixedBody = document.querySelector(
        ".ant-table-fixed-left .ant-table-body-outer .ant-table-fixed"
      );
      if (fixedHead) {
        fixedHead.style.width = width + "px";
        fixedBody.style.width = width + "px";
      }
    },
    getDraggingMap(tbCols, draggingMap, nodeLevel) {
      tbCols.forEach((col, index) => {
        col.nodeLevel = nodeLevel;
        col.isEndNode = index == tbCols.length - 1;
        this.maxLevel = Math.max(this.maxLevel, nodeLevel);
        if (col.children) {
          col.leafNode = false;
          this.getDraggingMap(col.children, draggingMap, nodeLevel + 1);
        } else {
          col.leafNode = true;
          const key = col.dataIndex || col.key; //这儿要求表格数据中要有这两个属性
          draggingMap[key] = col.width || 0;
        }
      });
    },
    getRenderCoL(key, tbCols) {
      let result = "";
      this._.forEach(tbCols, (item) => {
        if (item.children) {
          result = this.getRenderCoL(key, item.children);
          return !result;
        } else {
          const k = item.dataIndex || item.key;
          if (k === key) {
            result = item;
            return false;
          }
        }
      });
      return result;
    },
  },
};
</script>
<style lang="less">
/* vue-draggable-resizable@2.1.0 begin */
.resize-table-th {
  position: relative;
  overflow: hidden;
}
.resize-table-th .table-draggable-handle {
  height: 100% !important;
  bottom: 0;
  left: auto !important;
  right: -5px;
  cursor: col-resize;
  touch-action: none;
}
/* 插件 end */
</style>

安装lodash

npm install lodash --save

在main.js中注册

import _ from 'lodash'
Vue.prototype._ = _ 
  • 2
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值