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 шт):

Автор решения: OPTIMUS PRIME

Если уже есть функция сортировки, можно уж добавить пару строчек, чтобы можно было пересортировать при клике на название столбика. И изменил название класса 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. домашнее задание))

  1. Сделайте проверку при клике: Если у текущей кнопки уже есть класс active, значит не нужно заново запускать сортировку.
  2. querySelectorAll("tr") и прочие коллекции элементов можно хранить в переменных вне функции, чтобы при каждой сортировке заново их не собирать.
  3. Можно ли сделать две функции для сортировки - одна для строк, другая для чисел, а перед сортировкой один раз выбрать нужную, чтобы на каждой итерации не проверять isNaN ?
→ Ссылка
Автор решения: webDev_

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>

→ Ссылка