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

New settings for text and fonts in CSS3

Text Shadow text-shadow: horizontal offset vertic...

Detailed tutorial on installing Protobuf 3 on Ubuntu

When to install If you use the protoc command and...

How to run the springboot project in docker

1. Click Terminal below in IDEA and enter mvn cle...

What are the differences between var let const in JavaScript

Table of contents 1. Repeated declaration 1.1 var...

How to install Docker on Raspberry Pi

Because the Raspberry Pi is based on ARM architec...

CSS to implement QQ browser functions

Code Knowledge Points 1. Combine fullpage.js to a...

Detailed explanation of MySQL redo log (redo log) and rollback log (undo logo)

Preface: The previous article described several c...

Basic structure of HTML documents (basic knowledge of making web pages)

HTML operation principle: 1. Local operation: ope...

React internationalization react-intl usage

How to achieve internationalization in React? The...

How to deploy LNMP architecture in docker

Environmental requirements: IP hostname 192.168.1...

Implementation of MySQL master-slave status check

1. Check the synchronization status of A and B da...

Detailed tutorial on installing centos8 on VMware

CentOS official website address https://www.cento...

Horizontal header menu implemented with CSS3

Result:Implementation Code html <nav class=&qu...

Detailed Example of CSS3 box-shadow Property

CSS3 -- Adding shadows (using box shadows) CSS3 -...