JS отсортированная таблица по столбцу в котором указан специальный класс для сортировки
Нуждаюсь в помощи с js для сортировки таблицы по столбцу, в котором указан класс на пример sorted-asc от минимального к большему
То есть если установлен класс sorted-asc, значит по загрузке страницы - таблица сортируется по столбцу в котором установлен class="sorted-asc"
<table class="table_sort">
<thead>
<tr class="text-center">
<th class="px-2">Напряжение</th>
<th class="px-2">Мощность</th>
<th class="px-2">Модель серводрайвера</th>
<th class="px-2 sorted-asc">Модель двигателя</th>
</tr>
</thead>
<tbody>
<tr class="text-center">
<td class="">1</td>
<td class="">2.5</td>
<td class="">mod2</td>
<td class="">serv3</td>
</tr>
<tr class="text-center">
<td class="">2</td>
<td class="">3.5</td>
<td class="">mod1</td>
<td class="">serv1</td>
</tr>
<tr class="text-center">
<td class="">3</td>
<td class="">5.5</td>
<td class="">mod4</td>
<td class="">serv2</td>
</tr>
<tr class="text-center">
<td class="">4</td>
<td class="">4.5</td>
<td class="">mod3</td>
<td class="">serv4</td>
</tr>
</tbody>
</table>
Ответы (2 шт):
Если уже есть функция сортировки, можно уж добавить пару строчек, чтобы можно было пересортировать при клике на название столбика. И изменил название класса sorted-asc на active, показалось - так легче читается) Комментарии в коде:
sort_table();
document.querySelectorAll(".table_sort th").forEach(th => {
th.addEventListener("click", function() {
// Кликнули на th: Находит и удаляет класс active,
// добавляет его на текущий th, запускает сортировку.
let th_active = document.querySelector(".table_sort th.active");
if (th_active) th_active.classList.remove("active");
this.classList.add("active");
sort_table();
});
});
/***/
function sort_table() {
let ths = document.querySelectorAll(".table_sort th");
let th_active = document.querySelector(".table_sort th.active");
let index = [].indexOf.call(ths, th_active);
// Номер th.active клетки среди остальных th
/***/
let tbody = document.querySelector(".table_sort tbody");
let trs = tbody.querySelectorAll("tr");
let sorted_trs = [...trs].sort(function(tr_1, tr_2) {
let a = tr_1.children[index].textContent.toLowerCase();
let b = tr_2.children[index].textContent.toLowerCase();
// tr_1.children[index] - <td> под номером index
// (тот же номер, что и у выбранного <th>)
if ( !isNaN(a-b) ) a = Number(a), b = Number(b);
return a < b ? 1 : -1;
});
sorted_trs.forEach( tr => tbody.appendChild(tr) );
// Когда получен отсортированный массив, остается заново вставить
// все элементы в tbody. Они окажутся в нужном порядке.
}
th.active::before {
content: "▼";
color: #0c0;
}
<table class="table_sort">
<thead>
<tr class="text-center">
<th class="px-2">Напряжение</th>
<th class="px-2">Мощность</th>
<th class="px-2">Модель серводрайвера</th>
<th class="px-2 active">Модель двигателя</th>
</tr>
</thead>
<tbody>
<tr class="text-center">
<td class="">1</td>
<td class="">2.5</td>
<td class="">mod2</td>
<td class="">serv3</td>
</tr>
<tr class="text-center">
<td class="">2</td>
<td class="">3.5</td>
<td class="">mod1</td>
<td class="">serv1</td>
</tr>
<tr class="text-center">
<td class="">3</td>
<td class="">5.5</td>
<td class="">mod4</td>
<td class="">serv2</td>
</tr>
<tr class="text-center">
<td class="">4</td>
<td class="">4.5</td>
<td class="">mod3</td>
<td class="">serv4</td>
</tr>
</tbody>
</table>
if ( !isNaN(a-b) ) a = Number(a), b = Number(b); - тут подвох в том, что прилетевший textContent - всегда строка, даже если в ней содержится число. Если сравнивать числа как строки (в алфавитном порядке), окажется что
console.log( "9" > "111" ) // true?!
Так и должно быть: в кодировке utf-8, символ "9" идет после символа "1". А строки сравниваются посимвольно. Первый символ "9" правда больше "1", дальше не проверяет - сразу дает true.
Поэтому эта строчка проверяет, если a и b содержат числа - берет и приводит их в числовой тип.
Справки:
P.s. домашнее задание))
- Сделайте проверку при клике: Если у текущей кнопки уже есть класс active, значит не нужно заново запускать сортировку.
querySelectorAll("tr")и прочие коллекции элементов можно хранить в переменных вне функции, чтобы при каждой сортировке заново их не собирать.- Можно ли сделать две функции для сортировки - одна для строк, другая для чисел, а перед сортировкой один раз выбрать нужную, чтобы на каждой итерации не проверять isNaN ?
const tableSort = document.querySelector(".table_sort");
const sort = tableSort => {
const thead = [...tableSort.querySelector("thead > tr").children],
tbody = tableSort.querySelector("tbody"),
children = [...tbody.children];
let key = -1, match;
thead.some(th => {
match = th.classList.toString().match(/(sorted([^\s]+)?)/);
key++;
return match !== null
});
if (!match) { return }
const sort = match[0].split("-");
children.sort((a, b) => {
return a.children[key].innerText > b.children[key].innerText
});
if (sort.indexOf("asc") > -1) { children.reverse() }
children.forEach(tr => tbody.appendChild(tr))
};
sort(tableSort);
<table class="table_sort">
<thead>
<tr class="text-center">
<th class="px-2">Напряжение</th>
<th class="px-2">Мощность</th>
<th class="px-2">Модель серводрайвера</th>
<th class="px-2 sorted-asc">Модель двигателя</th>
</tr>
</thead>
<tbody>
<tr class="text-center">
<td class="">1</td>
<td class="">2.5</td>
<td class="">mod2</td>
<td class="">serv3</td>
</tr>
<tr class="text-center">
<td class="">2</td>
<td class="">3.5</td>
<td class="">mod1</td>
<td class="">serv1</td>
</tr>
<tr class="text-center">
<td class="">3</td>
<td class="">5.5</td>
<td class="">mod4</td>
<td class="">serv2</td>
</tr>
<tr class="text-center">
<td class="">4</td>
<td class="">4.5</td>
<td class="">mod3</td>
<td class="">serv4</td>
</tr>
</tbody>
</table>