задний план
Element UI — это популярная платформа пользовательского интерфейса Vue.js для ПК, а ее библиотека компонентов может в основном удовлетворить большинство распространенных потребностей бизнеса. Но иногда существуют очень индивидуальные требования, которым сам компонент может не соответствовать. Я наткнулся на это недавно в проекте.
Многие страницы должны использовать компонент формыel-table. если не даноel-table-columnУказывает ширину, которая по умолчанию будет равномерно распределена между остальными столбцами. В случае большого количества столбцов, еслиel-tableШирина ограничена контейнером, а содержимое ячейки обертывается. Принудительно не переносите содержимое, и содержимое либо прокручивается внутри ячейки, либо переполняется, либо обрезается.
Желаемый эффект продукта: содержимое остается отображаемым в одной строке, расстояние между столбцами остается постоянным, а таблица выходит за пределы контейнера, чтобы обеспечить горизонтальную прокрутку.el-table-columnОн поддерживает настройку фиксированной ширины, которая также может удовлетворить это требование, когда ширина содержимого предсказуема. Проблема заключается в том, как сделать так, чтобы ширина столбца динамически адаптировалась к ширине содержимого. В официальной документации я такой опции не нашел, должно быть, сам компонент ее не поддерживает.
Технические решения
Поэтому я подумал о решении для динамического расчета ширины контента. Кто-то в Интернете также упомянул эту идею.Метод заключается в том, чтобы рассчитать ширину в соответствии с количеством символов в содержании. Этот подход имеет несколько ограничений:
- Содержимое должно быть текстовым
- Разные символы имеют разную ширину, и результат расчета недостаточно точен.
- Перед рендерингом необходимо манипулировать данными, что не способствует разделению.
Я принял другую идею, заключающуюся в динамическом вычислении ширины контента, но в соответствии с фактической шириной визуализируемого элемента 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-…, добро пожаловать всем, чтобы дать нам свой совет и звезду!
Суммировать
Это решение является своего рода хаком, просто учитывая требования к реализации, могут быть некоторые недостатки в других аспектах, таких как небольшая засветка после рендеринга (потому что ширина должна быть перенастроена, будет перекомпоновка). Но, судя по итоговому эффекту, он вполне удовлетворительный, по крайней мере, продакт-менеджер ушел со своим двухметровым ножом... Для этого эффекта он полдня просидел перед моим компьютером и настоял на том, чтобы я его добился. ! Под принуждением прикосновения рук я наконец закончил дело...
Ради этого логотипа почему бы не обратить внимание?