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

mysql query data for today, this week, this month, and last month

today select * from table name where to_days(time...

Detailed tutorial on installing Tomcat9 windows service

1. Preparation 1.1 Download the tomcat compressed...

Simple example of using Docker container

Table of contents 1. Pull the image 2. Run the im...

What should I do if I can't view the source file of a web page?

Q: Whether using Outlook or IE, when you right-cl...

Sample code for testing technology application based on Docker+Selenium Grid

Introduction to Selenium Grid Although some new f...

Detailed explanation of MySQL database paradigm

Preface: I have often heard about database paradi...

Front-end advanced teaching you to use javascript storage function

Table of contents Preface Background Implementati...

Full analysis of web page elements

Relative Length Units em Description: Relative len...

JS ES new feature of variable decoupling assignment

Table of contents 1. Decoupled assignment of arra...

How to invert the implementation of a Bezier curve in CSS

First, let’s take a look at a CSS carousel animat...

WeChat Mini Program Lottery Number Generator

This article shares the specific code of the WeCh...

Perform data statistics on different values ​​of the same field in SQL

Application scenario: It is necessary to count th...

MySQL merge and split by specified characters example tutorial

Preface Merging or splitting by specified charact...

The complete usage of setup, ref, and reactive in Vue3 combination API

1. Getting started with setUp Briefly introduce t...

How to use node to implement static file caching

Table of contents cache Cache location classifica...