(Почти) идеально подходит для адаптации ширины столбца el-table

Vue.js

задний план

Element UI — это популярная платформа пользовательского интерфейса Vue.js для ПК, а ее библиотека компонентов может в основном удовлетворить большинство распространенных потребностей бизнеса. Но иногда существуют очень индивидуальные требования, которым сам компонент может не соответствовать. Я наткнулся на это недавно в проекте.

Многие страницы должны использовать компонент формыel-table. если не даноel-table-columnУказывает ширину, которая по умолчанию будет равномерно распределена между остальными столбцами. В случае большого количества столбцов, еслиel-tableШирина ограничена контейнером, а содержимое ячейки обертывается. Принудительно не переносите содержимое, и содержимое либо прокручивается внутри ячейки, либо переполняется, либо обрезается.

Желаемый эффект продукта: содержимое остается отображаемым в одной строке, расстояние между столбцами остается постоянным, а таблица выходит за пределы контейнера, чтобы обеспечить горизонтальную прокрутку.el-table-columnОн поддерживает настройку фиксированной ширины, которая также может удовлетворить это требование, когда ширина содержимого предсказуема. Проблема заключается в том, как сделать так, чтобы ширина столбца динамически адаптировалась к ширине содержимого. В официальной документации я такой опции не нашел, должно быть, сам компонент ее не поддерживает.

Технические решения

Поэтому я подумал о решении для динамического расчета ширины контента. Кто-то в Интернете также упомянул эту идею.Метод заключается в том, чтобы рассчитать ширину в соответствии с количеством символов в содержании. Этот подход имеет несколько ограничений:

  1. Содержимое должно быть текстовым
  2. Разные символы имеют разную ширину, и результат расчета недостаточно точен.
  3. Перед рендерингом необходимо манипулировать данными, что не способствует разделению.

Я принял другую идею, заключающуюся в динамическом вычислении ширины контента, но в соответствии с фактической шириной визуализируемого элемента DOM это может решить три вышеупомянутые проблемы.

Как это сделать? Глядя на визуализированный элемент DOM,el-tableЗаголовок и контент используют нативныйtable,пройти черезcolgroupУстановите ширину каждого столбца. Просто начните здесь,colизnameзначение атрибута и соответствующийtdизclassЗначения согласованы, так что вы можете просмотреть все ячейки в соответствующем столбце, найти ячейку с наибольшей шириной и использовать ширину ее содержимого плюс поля в качестве ширины столбца.

Реализация

Как рассчитать ширину контента? Это более важный шаг. Каждая отображаемая ячейка имеет.cellкласс, сwhite-space: nowrap; overflow: auto;Установите запрет на перевод строки, прокрутку после превышения содержимого и установку одновременно.display: inline-block;для расчета фактической ширины контента. Таким образом, конечная ширина может быть передана через.cellэлементальscrollWidthсвойства получают.

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}`),
    ];
    // 忽略加了"leave-alone"类的列
    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);
    });
  });
}

Процесс исследования в середине громоздок, но окончательная реализация кода очень лаконична. Когда запускается расчет ширины столбца? Естественно после завершения рендеринга компонента. Чтобы облегчить повторное использование, я принял способ пользовательской директивы Vue.

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

Сделав еще один шаг, я обернул плагин Vue под названиемv-fit-columns, который был опубликован в репозитории npm и может использоваться сразу после установки. Установить:

npm install v-fit-columns --save

Представлять:

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

использовать:

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

Репозиторий исходного кода находится здесь:GitHub.com/Хорошо, старались/V-…, добро пожаловать всем, чтобы дать нам свой совет и звезду!

Суммировать

Это решение является своего рода хаком, просто учитывая требования к реализации, могут быть некоторые недостатки в других аспектах, таких как небольшая засветка после рендеринга (потому что ширина должна быть перенастроена, будет перекомпоновка). Но, судя по итоговому эффекту, он вполне удовлетворительный, по крайней мере, продакт-менеджер ушел со своим двухметровым ножом... Для этого эффекта он полдня просидел перед моим компьютером и настоял на том, чтобы я его добился. ! Под принуждением прикосновения рук я наконец закончил дело...

Ради этого логотипа почему бы не обратить внимание?