Ant designing vue table to achieve a complete example of scalable columns

Ant designing vue table to achieve a complete example of scalable columns

Perfect solution to the scalable column problem of ant-design-vue table, realizing scalable columns in fixed columns and multi-level headers

I thought this thing would be easy to use, because examples have been given on the official website. However, we still cannot trust the official website too much. The official website can only provide the most basic ones, and our normal usage scenarios are often much more complicated, such as fixed columns, fixed headers, built-in checkbox columns, and multi-level headers. To meet these situations, it is often necessary to develop your own.

1. First of all, I copied Chiang’s official example, but it couldn’t be dragged out.

After comparing with the official one, I found that the CSS was different, so I added the first change. Because the style inline style has its own translate attribute, I directly removed right: 0 and only left -5. Set the height to 100%.

.resize-table-th {
    position: relative;
    .table-draggable-handle {
      height: 100% !important;
      bottom: 0;
      left: -5px !important;
      cursor: col-resize;
      touch-action: none;
      position: absolute;
    }
  }

2. This time you can see that the translate attribute changes in real time after each drag, but the cell does not become wider or move.

So I checked the elements again and found that the width of th was changing, but the width attribute of colGroup did not change. So I started looking for the corresponding colGroup child element col. Finally I found it, and then I modified the width attribute of colGroup's col while dragging. This way you can follow the changes.

3. Next, I found that stretching would cause a bug when the columns and headers were fixed.

Looking at the code, I found that when it is a fixed column or a fixed header, thead and tbody are actually on different tables. At this time, you need to find all colGroups to measure col and change the width. This handles the stretching of the fixed header. However, in the case of fixed columns, you still need to set CSS separately, find table-fixed-left and reset the width.

Here is some code

According to the current th, determine which child node th is the parent element, corresponding to which col node of colGroup

const loopDom = ss => {
  if (ss.previousSibling !== null) {
    thDomIndex++;
    loopDom(ss.previousSibling);
  }
};

Reset the width of fixed columns (only handles left float)

function 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";
  }
}

Solve the problem of multi-level header expansion column

Recursively traverse the array and get the width

getDraggingMap(tbCols, draggingMap) {
      tbCols.forEach(col => {
        if (col.children) {
          this.getDraggingMap(col.children, draggingMap);
        } else {
          const key = col.dataIndex || col.key; //The table data must have these two attributes draggingMap[key] = col.width || 0;
        }
      });
    },

Recursively traverse the array and get the current column (this recursion is really annoying, I don’t know how you feel about writing recursion)

// Processing multi-level headers 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;
    }

Recursively traverse the array to obtain the index of the multi-level header operation column (the recursion is also unbearable. At the beginning, the last renturn is missing and it keeps running wrong. The shadow area of ​​the recursion is infinite)

 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;
        };

Here is the complete code

This is a js file, which introduces the table main file through mixin. Table adds

:components="drag(columnKeys)"
//mixins/tableDragResize.js
import Vue from "vue";
import VueDraggableResizable from "vue-draggable-resizable";
Vue.component("vue-draggable-resizable", VueDraggableResizable);

export default {
  data() {
    return {
      maxLevel: 1
    };
  },
  methods: {
    drag(columns) {
      return {
        header: {
          cell: this.initDrag(columns)
        }
      };
    },
    /**
     * @param { table 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 = {};
        // Processing multi-level headers col = this.getRenderCoL(key, tbCols);
        if (!col || !col.width) {
          //Here the table data must have a width attribute. If not, the following dragging will not be executed. 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";
          });
          this.resetFixedColumns(col.width);
        };
        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 = () => {};

        return (
          <th {...restProps} width={draggingState[key]} class="resize-table-th" dataIndex={col.key}>
            {children}
            <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>
        );
      };
    },
    getResizableHandler(col) {
      // let baseH = thDom.getBoundingClientRect().height;
      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; //The table data must have these two attributes 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;
    }
  }
};

Postscript Perfect solution to the expansion column of multi-level table header Modify the original getDraggingMap method, add nodeLevel level, isEndNode is the last node under the cover level, and this.maxLevel records the maximum level

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; //The table data must have these two attributes draggingMap[key] = col.width || 0;
}
});
},

Add a method to handle the height of table-draggable-handle

View image

insert image description here

The draggable area is the red area. To achieve this effect, the following processing is required

First remove the height in the CSS: 100%;
Then set the component height when rendering as follows

h = {this.getResizableHandler(col)}

size is the table size

getResizableHandler(col) {
      // let baseH = thDom.getBoundingClientRect().height;
      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;
    },

end

The above is the details of ant design vue table to achieve scalable columns. For more information about ant design vue table scalable columns, please pay attention to other related articles on 123WORDPRESS.COM!

You may also be interested in:
  • vue public list selection component, reference Vant-UI style
  • Ant Design Vue table column super long display ... and add prompt example
  • Vue+vant realizes batch countdown function of product list

<<:  How to install mysql via yum on centos7

>>:  How to detect whether a file is damaged using Apache Tika

Recommend

CSS code to achieve background gradient and automatic full screen

CSS issues about background gradient and automati...

How to write high-quality JavaScript code

Table of contents 1. Easy to read code 1. Unified...

Solution to Vue3.0 error Cannot find module'worker_threads'

I'll record my first attempt at vue3.0. When ...

MySQL configuration master-slave server (one master and multiple slaves)

Table of contents Ideas Host Configuration Modify...

Steps to customize icon in Vue

ant-design-vue customizes the use of Ali iconfont...

Alibaba Cloud Server Domain Name Resolution Steps (Tutorial for Beginners)

For novices who have just started to build a webs...

VMware Workstation installation Linux (Ubuntu) system

For those who don't know how to install the s...

MySQL compression usage scenarios and solutions

Introduction Describes the use cases and solution...

MySQL advanced learning index advantages and disadvantages and rules of use

1. Advantages and Disadvantages of Indexes Advant...

More Ways to Use Angle Brackets in Bash

Preface In this article, we will continue to expl...

MySQL import and export backup details

Table of contents 1. Detailed explanation of MySQ...

Solution to the problem of session failure caused by nginx reverse proxy

A colleague asked for help: the login to the back...

JS function call, apply and bind super detailed method

Table of contents JS function call, apply and bin...

A comprehensive summary of frequently used statements in MySQL (must read)

The knowledge points summarized below are all fre...

How to hide the border/separation line between cells in a table

Only show the top border <table frame=above>...