Выделение стилем CSS в массиве JS-Script - динамическая таблица
Имеется таблица: Всё работает прекрасно. Но хотел бы применить стиль css в данных массива "data", к примеру - выделить название отделов ("Руководство" в примере) стилями. Как такое можно внедрить в данную конструкцию?
let data = [
"► Руководство;;;;",
"Директор;Пупкин Василий Васильевич;223-322;8 900-000-00-00;[email protected]",
"Зам. директора;Тигренко Лев Леопардович;322-223;8 900-000-00-01;[email protected]"];
function clearTable(table) {
for (var i = table.rows.length - 1; i > 0; i--) {
table.deleteRow(i);
}
}
function buildCell(row, entry, searchQuery) {
var cell = row.insertCell(-1);
highlight = new RegExp(searchQuery, "i");
if (searchQuery) {
cell.innerHTML = entry.replace(highlight, "<mark style='background-color:#0078d7; color:#ffffff;'>" + "$&" + "</mark>");
} else {
cell.appendChild(document.createTextNode(entry));
}
}
function buildTable(tableID, data, searchQuery) {
var table = document.getElementById(tableID);
clearTable(table)
for (i = 0; i < data.length; i++) {
var row = table.insertRow(-1);
slots = data[i].split(";");
for (j = 0; j < 5; j++) {
buildCell(row, slots[j], searchQuery);
}
}
}
buildTable("dataTable", data, "")
var keyupStack = [];
var keyword = document.getElementById('keyword');
keyword.addEventListener('keyup', function() {
keyupStack.push(1);
setTimeout(function() {
keyupStack.pop();
if (keyupStack.length === 0) {
var buf = '.*?' + this.value.replace(/(.)/g, "$1");
var reg = new RegExp(buf, 'i');
var filteredLists = data.filter(function(d) {
return reg.test(d);
});
buildTable("dataTable", filteredLists, this.value);
}
}.bind(this), 300);
});
tr:nth-child(2n+1) {
background: #f9f9f9; /* Цвет фона */
}
tr:nth-child(1) {
background: #cccccc; /* Цвет фона */
}
td{padding-left: 4px; padding-right: 4px;
border: solid;
border-color: #cccccc;
border-width: 1px;}
th {border: solid;
border-color: #b1b1b1;
border-width: 1px;}
#foundation{padding: 4px 4px 4px 4px;
color:#121c4b;
width:fit-content;
margin-left: auto;
margin-right: auto;
margin-bottom: 20pt;
line-height: 13px;
top:14pt;
text-align: left;
font-family: 'PT Sans', 'Roboto', 'Helvetica Nue', sans-serif;
font-size: 8pt;
position:relative;}
<div id="foundation">
<div style="position:fixed; text-align: center; min-width:228pt; max-width:600pt; width: 22vw; left:50%; right:50%; transform: translate(-50%, -50%); margin-top: -12px; margin-bottom: 24px; background-color:rgba(255,255,255,0.80); padding-top: 8pt;">
<span style="font-size: 10pt; font-weight: bold;">Поиск:</span> <input type="text" id="keyword" style="height: 12pt">
<ul id="list">
</ul>
</div>
<table id="dataTable" border="0" cellspacing="0" cellpadding="0" style="margin-left: auto; margin-right: auto; margin-top: 12pt; margin-bottom: 16px; border-collapse: collapse;">
<tr>
<th style="padding-left: 6px; padding-right: 6px;">Должность</th>
<th style="padding-left: 6px; padding-right: 6px;">ФИО</th>
<th style="padding-left: 6px; padding-right: 6px;">телефон отдела</th>
<th style="padding-left: 6px; padding-right: 6px;">телефон сотрудника</th>
<th style="padding-left: 6px; padding-right: 6px;">e-mail</th>
</tr>
</table>
</div>
</div>
Ответы (2 шт):
Убрана зависимость от html и написано с помощью JS класса. Добавлена возможность добавления CSS свойств/CSS классов для ячеек данных. Изменён формат данных для таблицы - без ;. Если принципиально нужно с ; - нужно будет отдельно написать функцию, которая будет форматировать массив со строками с ; в массив, который тут используется.
class DirectoryTable {
#container;
#data;
#headers;
#highlightColor;
#highlightTextColor;
#debounce;
#keyupStack = [];
#table;
#keywordInput;
constructor({
container,
data,
headers = [],
highlightColor = '#0078d7',
highlightTextColor = '#ffffff',
debounce = 300
}) {
this.#container = container;
this.#data = data;
this.#headers = headers;
this.#highlightColor = highlightColor;
this.#highlightTextColor = highlightTextColor;
this.#debounce = debounce;
this.#createLayout();
this.#buildTable(this.#data, "");
this.#keywordInput.addEventListener("keyup", this.#onKeyUp);
}
#createLayout() {
this.#container.innerHTML = "";
const searchPanel = document.createElement("div");
searchPanel.className = "search-panel";
searchPanel.innerHTML = `
<span class="search-label">Поиск:</span>
<input type="text" class="search-input">
<ul class="search-suggestions"></ul>
`;
this.#container.appendChild(searchPanel);
this.#keywordInput = searchPanel.querySelector("input");
this.#table = document.createElement("table");
this.#table.className = "data-table";
const headerRow = this.#table.insertRow(-1);
headerRow.className = "header-row";
this.#headers.forEach(text => {
const th = document.createElement("th");
th.className = "th-cell";
th.textContent = text;
headerRow.appendChild(th);
});
this.#container.appendChild(this.#table);
}
#clearTable() {
while (this.#table.rows.length > 1) {
this.#table.deleteRow(-1);
}
}
#buildCell(row, cellData, searchQuery) {
const td = row.insertCell(-1);
const value = (cellData && typeof cellData.value !== "undefined") ? String(cellData.value) : "";
// Добавление классов
if (Array.isArray(cellData?.className)) {
td.classList.add(...cellData.className);
}
// Добавление стилей (не перезаписывает существующие)
if (cellData?.style && typeof cellData.style === "object") {
for (const [key, val] of Object.entries(cellData.style)) {
td.style[key] = val;
}
}
// Подсветка совпадений
const regex = new RegExp(searchQuery, "i");
if (searchQuery && regex.test(value)) {
td.innerHTML = value.replace(
regex,
`<mark style="background-color:${this.#highlightColor}; color:${this.#highlightTextColor};">$&</mark>`
);
} else {
td.textContent = value;
}
}
#buildTable(data, searchQuery) {
this.#clearTable();
data.forEach(rowData => {
const row = this.#table.insertRow(-1);
for (let i = 0; i < this.#headers.length; i++) {
this.#buildCell(row, rowData[i] || {}, searchQuery);
}
});
}
#onKeyUp = () => {
this.#keyupStack.push(1);
setTimeout(() => {
this.#keyupStack.pop();
if (this.#keyupStack.length === 0) {
const query = this.#keywordInput.value.trim();
const regex = new RegExp(".*?" + query.replace(/(.)/g, "$1"), "i");
const filtered = this.#data.filter(row =>
row.some(cell => cell?.value && regex.test(String(cell.value)))
);
this.#buildTable(filtered, query);
}
}, this.#debounce);
}
}
const headers = ["Должность", "ФИО", "телефон отдела", "телефон сотрудника", "e-mail"];
const data = [
[{
value: "► Административно-управленческий персонал",
className: ["group-row", "text-bold"],
style: {
color: "red",
border: "2px solid currentColor"
}
},
{}, {}, {}, {}
],
[{
value: "Директор",
className: ["title"]
},
{
value: "Пупкин Василий Васильевич"
},
{
value: "223-322"
},
{
value: "8 900-000-00-00",
className: ["phone"]
},
{
value: "[email protected]"
}
],
[{
value: "Зам. директора"
},
{
value: "Тигренко Лев Леопардович"
},
{
value: "322-223"
},
{
value: "8 900-000-00-01",
className: ["phone"],
style: {
fontStyle: "italic"
}
},
{
value: "[email protected]"
}
]
];
new DirectoryTable({
container: document.getElementById("foundation"),
data: data,
headers: headers
});
html {
font-size: 24px;
}
.foundation {
padding: 4px;
color: #121c4b;
width: fit-content;
margin: 0 auto 1.25rem auto;
/* 20pt ≈ 26.67px ≈ 1.25rem */
line-height: 1.1rem;
top: 1rem;
/* 14pt ≈ 18.67px ≈ 1rem */
text-align: left;
font-family: 'PT Sans', 'Roboto', 'Helvetica Neue', sans-serif;
font-size: 0.5rem;
/* 8pt ≈ 10.67px ≈ 0.5rem */
position: relative;
}
.search-panel {
position: fixed;
text-align: center;
min-width: 304px;
/* 228pt ≈ 304px */
max-width: 800px;
/* 600pt ≈ 800px */
width: 22vw;
left: 50%;
right: 50%;
transform: translate(-50%, -50%);
margin-top: -12px;
margin-bottom: 24px;
background-color: rgba(255, 255, 255, 0.8);
padding-top: 0.5rem;
/* 8pt ≈ 10.67px ≈ 0.5rem */
}
.search-label {
font-size: 0.625rem;
/* 10pt ≈ 13.3px ≈ 0.625rem */
font-weight: bold;
}
.search-input {
height: 0.75rem;
/* 12pt ≈ 16px ≈ 1rem, but slightly smaller */
}
.data-table {
margin: 0.75rem auto 1rem auto;
/* 12pt ≈ 16px, 16px ≈ 1rem */
border-collapse: collapse;
}
.header-row {
background: #cccccc;
}
.data-table tr:nth-child(2n+1):not(.header-row) {
background: #f9f9f9;
}
.th-cell {
padding: 0 0.375rem;
/* 6px ≈ 0.375rem */
border: 1px solid #b1b1b1;
}
.data-table td {
padding: 0 0.25rem;
/* 4px ≈ 0.25rem */
border: 1px solid #cccccc;
}
<div id="foundation" class="foundation">
</div>
Немного учим конструктор в функции buildTable отмечать строки таблицы по ключевому знаку. Код легко обучается проверкой всей ячейки или всей строки. Цвет во вкусу...
function buildTable(tableID, data, searchQuery) {
let table = document.getElementById(tableID);
clearTable(table);
for (i = 0; i < data.length; i++) {
let row = table.insertRow(-1);
// row должна начинаться с ключа из примера
if (data[i]?.slice(0, 1) === '►') row.style.backgroundColor='#fcc';
// или содержит ключ где угодно в row
// if (data[i]?.includes('►')) row.style.backgroundColor='#fcc';
slots = data[i]?.split(";");
// или можно по тексту первой ячейки красить
// if (slots[0] === '► Руководство') row.style.backgroundColor='#fcc';
for (j = 0; j < 5; j++) {
buildCell(row, slots[j], searchQuery);
}; // этот цикл можно заменить на динамический
// и строить таблицу по полностью по 'data'
// slots.forEach(e => buildCell(row, e, searchQuery));
// но тогда весь код переписывать надо
};
};