vue perfectly realizes el-table column width adaptation

vue perfectly realizes el-table column width adaptation

background

Element UI is a popular Vue.js UI framework on PC. Its component library can basically meet most common business needs. But sometimes there are some highly customized requirements that the components themselves may not be able to meet. I encountered this recently in a project.

Many pages require the table component el-table. If no width is specified for el-table-column, it will be evenly distributed among the remaining columns by default. When there are many columns, if the width of el-table is limited to the container, the content in the cell will wrap. Force no line wrapping, the content will either scroll within the cell or overflow or be truncated.

The desired effect of the product is: the content is displayed in a single row, the column spacing is consistent, and the table exceeds the container to allow horizontal scrolling. el-table-column supports setting a fixed width, which can meet this requirement when the content width is predictable. The problem is how to make the column width dynamically adapt to the width of the content. I didn't find such an option in the official documentation, probably because the component itself does not support it.

Technical Solution

So I thought of a solution to dynamically calculate the content width. Some people have mentioned this idea online, and the approach is to calculate the width based on the number of characters in the content. This approach has several limitations:

  • Content must be text
  • Different characters have different widths, and the settlement results are not accurate enough
  • Need to manipulate data before rendering, which is not conducive to decoupling

I adopted another idea, which is to dynamically calculate the content width, but based on the actual rendered DOM element width, which can solve the above three problems.

How to do it specifically? By looking at the rendered DOM elements, it is found that the header and content of el-table use a native table respectively, and the width of each column is set by colgroup. Let's start from here. The name attribute value of col is consistent with the class value of the corresponding td. In this way, we can traverse all cells of the corresponding column, find the cell with the largest width, and use its content width plus a margin as the width of the column.

Specific implementation

How to calculate content width? This is a relatively critical step. After rendering, each cell has a .cell class, which is set to not allow line breaks with white-space: nowrap; overflow: auto;. The content can be scrolled if it exceeds the limit, and display: inline-block; is set to calculate the actual content width. In this way, the final width can be obtained through the scrollWidth property of the .cell element.

function adjustColumnWidth(table) {
  const colgroup = table.querySelector("colgroup");
  const colDefs = [...colgroup.querySelectorAll("col")];
  colDefs.forEach((col) => {
    const clsName = col.getAttribute("name");
    const cells = [
      ...table.querySelectorAll(`td.${clsName}`),
      ...table.querySelectorAll(`th.${clsName}`),
    ];
    // Ignore columns with the "leave-alone" class if (cells[0]?.classList?.contains?.("leave-alone")) {
      return;
    }
    const widthList = cells.map((el) => {
      return el.querySelector(".cell")?.scrollWidth || 0;
    });
    const max = Math.max(...widthList);
    const padding = 32;
    table.querySelectorAll(`col[name=${clsName}]`).forEach((el) => {
      el.setAttribute("width", max + padding);
    });
  });
}

The exploration process in the middle is rather cumbersome, but the final code implementation is very concise. When is the column width calculation triggered? Naturally, after the component rendering is completed. In order to facilitate reuse, I adopted the Vue custom directive approach.

Vue.directive("fit-columns", {
  update() {},
  bind() {},
  inserted(el) {
    setTimeout(() => {
      adjustColumnWidth(el);
    }, 300);
  },
  componentUpdated(el) {
    el.classList.add("r-table");
    setTimeout(() => {
      adjustColumnWidth(el);
    }, 300);
  },
  unbind() {},
});

Furthermore, I have encapsulated a Vue plug-in called v-fit-columns, which has been published to the npm repository and can be directly installed and used.
Install:

npm install v-fit-columns --save

Import:

import Vue from 'vue';
import Plugin from 'v-fit-columns';
Vue.use(Plugin);

use:

<el-table v-fit-columns>
  <el-table-column label="No." type="index" class-name="leave-alone"></el-table-column>
  <el-table-column label="Name" prop="name"></el-table-column>
  <el-table-column label="Age" prop="age"></el-table-column>
</el-table>

The source code repository is here: https://github.com/kaysonli/v-fit-columns. Welcome to give us your comments and stars!

Summarize

This solution is somewhat of a hack, and is only concerned with meeting the requirements. It may have some flaws in other aspects, such as a slight flash after rendering (because the width needs to be readjusted, which will cause reflow). However, judging from the final effect, it is quite satisfactory.

The above is the detailed content of vue's perfect implementation of el-table column width adaptation. For more information about vue's implementation of el-table column width adaptation, please pay attention to other related articles on 123WORDPRESS.COM!

You may also be interested in:
  • Vue uses el-table to implement a circular carousel data list
  • Detailed explanation of the writing method of VUE2.0+ElementUI2.0 table el-table loop dynamic column rendering
  • The table in vue+Element is editable (select drop-down box)
  • Vue uses el-table to loop and generate tables

<<:  How to modify the firewall on a Linux server to allow remote access to the port

>>:  Windows 10 + mysql 8.0.11 zip installation tutorial detailed

Recommend

How to develop Java 8 Spring Boot applications in Docker

In this article, I will show you how to develop a...

Sample code for programmatically processing CSS styles

Benefits of a programmatic approach 1. Global con...

The most common declaration merge in TS (interface merge)

Table of contents 1. Merge interface 1.1 Non-func...

MySQL 8.0.16 installation and configuration tutorial under Windows 10

This article shares with you the graphic tutorial...

How to use IDEA to configure tomcat and create JSP files

Before using idea to write JSP files, you need to...

Ubuntu 16.04 installation tutorial under VMware 12

This article shares with you the installation tut...

jQuery realizes the shuttle box effect

This article example shares the specific code of ...

Java example code to generate random characters

Sample code: import java.util.Random; import java...

Echart Bar double column chart style most complete detailed explanation

Table of contents Preface Installation and Config...

react-diagram serialization Json interpretation case analysis

The goal of this document is to explain the Json ...

JavaScript Array Methods - Systematic Summary and Detailed Explanation

Table of contents Common array methods Adding and...

MySQL Server 8.0.3 Installation and Configuration Methods Graphic Tutorial

This document records the installation and config...

Linux kernel device driver kernel time management notes

/****************** * Linux kernel time managemen...