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

Handwriting implementation of new in JS

Table of contents 1 Introduction to the new opera...

How familiar are you with pure HTML tags?

The following HTML tags basically include all exis...

How to remotely connect to the cloud server database using Navicat

It is very convenient to connect to a remote serv...

MySQL max_allowed_packet setting

max_allowed_packet is a parameter in MySQL that i...

The latest Linux installation process of tomcat8

Download https://tomcat.apache.org/download-80.cg...

Before making a web page, let’s take a look at these so-called specifications

This article has compiled some so-called specific...

Example of adding music video to HTML page

1. Video tag Supports automatic playback in Firef...

Solution for Nginx installation without generating sbin directory

Error description: 1. After installing Nginx (1.1...

Installation and configuration of mysql 8.0.15 under Centos7

This article shares with you the installation and...

How to Run a Command at a Specific Time in Linux

The other day I was using rsync to transfer a lar...

Detailed explanation of MySQL EXPLAIN output columns

1. Introduction The EXPLAIN statement provides in...

How to track users with JS

Table of contents 1. Synchronous AJAX 2. Asynchro...

JS calculates the probability of winning based on the prize weight

Table of contents 1. Example scenario 1.1. Set th...

MySQL randomly extracts a certain number of records

In the past, I used to directly order by rand() t...

Detailed explanation of MySQL deadlock and database and table sharding issues

Record the problem points of MySQL production. Bu...