Сортировка таблицы на Js (table sort) | Блог веб-разработчика MaxGraph

Сортировка таблицы на Js (table sort)

Привет! Сегодня весьма интересная тема - сортировка таблиц. Покажу, как сортировать по алфавиту, по числовым значениям, а так же красивую "последовательную" сортировку. Поехали!

Вступление

Сама по себе сортировка таблицы довольно обыденная фича для сайтов, ведь везде нужно как-то откалибровать данные под свои нужны. Сегодня мы как раз и рассмотрим, как сделать сортировку таблицы на Js с использованием SortElements.js.

HTML-разметка

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
<table class="table__one">
  <thead>
    <td class="name">Наименование работы</td>
    <td class="week" data-filter="one">Еженедельно</td>
    <td class="month" data-filter="two">Ежемесячно</td>
    <td class="kvar" data-filter="three">Квартально</td>
    <td class="polu" data-filter="four">Полугодично</td>
    <td class="year" data-filter="five">Раз в год</td>
  </thead>
  <tr data-filter-one="true">
    <td class="named">
      <span>Арбуз, чтобы было первым по алфавиту</span>
    </td>
    <td class="checks">
      <img src="https://image.flaticon.com/icons/svg/128/128384.svg" alt="">
    </td>
    <td class="checks"></td>
    <td class="checks"></td>
    <td class="checks"></td>
    <td class="checks"></td>
  </tr>
  <tr data-filter-four="true">
    <td class="named">
      <span>Павел, чтобы было в конце</span>
    </td>
    <td class="checks"></td>
    <td class="checks"></td>
    <td class="checks"></td>
    <td class="checks">
      <img src="https://image.flaticon.com/icons/svg/128/128384.svg" alt="">
    </td>
    <td class="checks"></td>
  </tr>
  <tr data-filter-five="true">
    <td class="named">
      <span>Борис, чтобы было вторым по алфавиту</span>
    </td>
    <td class="checks"></td>
    <td class="checks"></td>
    <td class="checks"></td>
    <td class="checks"></td>
    <td class="checks">
      <img src="https://image.flaticon.com/icons/svg/128/128384.svg" alt="">
    </td>
  </tr>
  <tr data-filter-three="true">
    <td class="named">
      <span>Николай, чтобы было третьим по алфавиту</span>
    </td>
    <td class="checks"></td>
    <td class="checks"></td>
    <td class="checks">
      <img src="https://image.flaticon.com/icons/svg/128/128384.svg" alt="">
    </td>
    <td class="checks"></td>
    <td class="checks"></td>
  </tr>
  <tr data-filter-two="true">
    <td class="named">
      <span>Ольга, чтобы было четвертым по алфавиту</span>
    </td>
    <td class="checks"></td>
    <td class="checks">
      <img src="https://image.flaticon.com/icons/svg/128/128384.svg" alt="">
    </td>
    <td class="checks"></td>
    <td class="checks"></td>
    <td class="checks"></td>
  </tr>
</table>
 
<table class="table__two">
  <thead>
    <tr>
      <td>Сортировка по числам</td>
    </tr>
  </thead>
  <tbody>
     <tr>
      <td>1098</td>
    </tr>
    <tr>
      <td>5</td>
    </tr>
    <tr>
      <td>1</td>
    </tr>
    <tr>
      <td>158</td>
    </tr>
  </tbody>
</table>
<table class="table__one">
  <thead>
    <td class="name">Наименование работы</td>
    <td class="week" data-filter="one">Еженедельно</td>
    <td class="month" data-filter="two">Ежемесячно</td>
    <td class="kvar" data-filter="three">Квартально</td>
    <td class="polu" data-filter="four">Полугодично</td>
    <td class="year" data-filter="five">Раз в год</td>
  </thead>
  <tr data-filter-one="true">
    <td class="named">
      <span>Арбуз, чтобы было первым по алфавиту</span>
    </td>
    <td class="checks">
      <img src="https://image.flaticon.com/icons/svg/128/128384.svg" alt="">
    </td>
    <td class="checks"></td>
    <td class="checks"></td>
    <td class="checks"></td>
    <td class="checks"></td>
  </tr>
  <tr data-filter-four="true">
    <td class="named">
      <span>Павел, чтобы было в конце</span>
    </td>
    <td class="checks"></td>
    <td class="checks"></td>
    <td class="checks"></td>
    <td class="checks">
      <img src="https://image.flaticon.com/icons/svg/128/128384.svg" alt="">
    </td>
    <td class="checks"></td>
  </tr>
  <tr data-filter-five="true">
    <td class="named">
      <span>Борис, чтобы было вторым по алфавиту</span>
    </td>
    <td class="checks"></td>
    <td class="checks"></td>
    <td class="checks"></td>
    <td class="checks"></td>
    <td class="checks">
      <img src="https://image.flaticon.com/icons/svg/128/128384.svg" alt="">
    </td>
  </tr>
  <tr data-filter-three="true">
    <td class="named">
      <span>Николай, чтобы было третьим по алфавиту</span>
    </td>
    <td class="checks"></td>
    <td class="checks"></td>
    <td class="checks">
      <img src="https://image.flaticon.com/icons/svg/128/128384.svg" alt="">
    </td>
    <td class="checks"></td>
    <td class="checks"></td>
  </tr>
  <tr data-filter-two="true">
    <td class="named">
      <span>Ольга, чтобы было четвертым по алфавиту</span>
    </td>
    <td class="checks"></td>
    <td class="checks">
      <img src="https://image.flaticon.com/icons/svg/128/128384.svg" alt="">
    </td>
    <td class="checks"></td>
    <td class="checks"></td>
    <td class="checks"></td>
  </tr>
</table>

<table class="table__two">
  <thead>
    <tr>
      <td>Сортировка по числам</td>
    </tr>
  </thead>
  <tbody>
     <tr>
      <td>1098</td>
    </tr>
    <tr>
      <td>5</td>
    </tr>
    <tr>
      <td>1</td>
    </tr>
    <tr>
      <td>158</td>
    </tr>
  </tbody>
</table>

В разметке можно увидеть две таблицы, для двух примеров — просто по алфавиту и для чисел. В общем и целом разметка обыденная, но в первой таблице есть еще специальные дата-атрибуты и классы, назначение которых будет объяснено дальше.

CSS

Думаю, CSS вам лучше посмотреть внутри codepen, тем более что тут совсем он неважен (почти).

JS

Самое интересное тут)

1
2
3
4
5
6
7
8
9
10
11
12
13
// по клику
$('.table__one thead td:first-child').click(function(e){
  $(this).parents('table').find('thead td').removeClass('active');
  $(this).addClass('active');
  e.preventDefault();
  function sort(selector) {
    selector.parents('table').find('tbody').find('tr').sortElements(function(a, b){
      return $(a).find('.named').find('span').text() > $(b).find('.named').find('span').text() ? 1 : -1;
    });
  }
  let selector = $(this);
  sort(selector);
});
// по клику
$('.table__one thead td:first-child').click(function(e){
  $(this).parents('table').find('thead td').removeClass('active');
  $(this).addClass('active');
  e.preventDefault();
  function sort(selector) {
    selector.parents('table').find('tbody').find('tr').sortElements(function(a, b){
      return $(a).find('.named').find('span').text() > $(b).find('.named').find('span').text() ? 1 : -1;
    });
  }
  let selector = $(this);
  sort(selector);
});

Не самый сложный код. Выбираем первый td из thead (в нашем случае это ячейка с текстом «Наименование работы». По клику на нее во-первых выставляем ей класс активности, чтобы точно было видно, что мы что-то выбрали. Это удобно.

Далее идет достаточно замысловатая запись, но все же она несложная. Пишем функцию sort, которая принимает в себя элемент, по которому мы кликнули. Через него находим нужный элемент и уже к нему применяем функцию sortElements, которая принимает два параметра — a и b. Это, по сути, все элементы, которые между собой будет сравнивать скрипт. Происходит сравнение, и скрипт меняет местами элементы так, как нам надо.

1
2
3
4
5
6
7
8
9
10
11
// для чисел
$('.table__two thead td').click(function(e){
  e.preventDefault();
  function sort(selector) {
    selector.parents('table').find('tbody').find('tr').sortElements(function(a, b){
      return parseInt($(a).find('td').text()) > parseInt($(b).find('td').text()) ? 1 : -1;
    });
  }
  let selector = $(this);
  sort(selector);
});
// для чисел
$('.table__two thead td').click(function(e){
  e.preventDefault();
  function sort(selector) {
    selector.parents('table').find('tbody').find('tr').sortElements(function(a, b){
      return parseInt($(a).find('td').text()) > parseInt($(b).find('td').text()) ? 1 : -1;
    });
  }
  let selector = $(this);
  sort(selector);
});

По сути, в коде для чисел подход 1 в 1, но тут мы должны обязательно перевести строку в число, чтобы корректно все отрабатывало.

1
2
3
4
5
6
7
8
9
10
// при загрузке страницы
$('.table__one thead td:first-child').each(function(){
  let selector = $(this);
  function sort(selector) {
    selector.parents('table').find('tbody').find('tr').sortElements(function(a, b){
      return $(a).find('.named').find('span').text() > $(b).find('.named').find('span').text() ? 1 : -1;
    });
  }
  sort(selector);
});
// при загрузке страницы
$('.table__one thead td:first-child').each(function(){
  let selector = $(this);
  function sort(selector) {
    selector.parents('table').find('tbody').find('tr').sortElements(function(a, b){
      return $(a).find('.named').find('span').text() > $(b).find('.named').find('span').text() ? 1 : -1;
    });
  }
  sort(selector);
});

По идее, мы можем и так — при загрузке страницы наша таблица сама отсортируется как ей нужно.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
// "последовательная" сортировка
$('.table__one thead td').not(':first-child').each(function(){
  $(this).click(function(e){
    e.preventDefault();
    $(this).parents('thead').find('td').removeClass('active');
    $(this).parents('thead').find('td').removeClass('taken');
    $(this).toggleClass('active');
    $(this).addClass('taken');
    let filter = $(this).attr('data-filter');
    console.log(filter)
    let filterArr = [];
    filterArr.push($(this).parents('table').find('tbody').find('tr[data-filter-' + filter + ' = "true"]'));
    $(this).parents('table').find('tbody').find('tr[data-filter-' + filter + ' = "true"]').remove();
    for(let i = 0; i < filterArr.length; i++) {
      $(this).parents('table').find('tbody').prepend(filterArr[i]);
      filterArr.pop(filterArr[i]);
    }
    let $tmpErt = $(this);
    $(this).parents('thead').find('td').not(':first-child').each(function(){
      if (!$(this).hasClass('taken')) {
        $tmpErt = $tmpErt.next();
        if ($tmpErt.length == 0) {
          $tmpErt = $(this).parents('thead').find('td:first-child').next();
        }
        let fil = $(this).parents('table').find('tbody').find('tr[data-filter-' + $tmpErt.attr('data-filter') + ' = "true"]');
        fil.remove();
        $(this).parents('table').find('tbody').append(fil);
        $(this).addClass('taken');
      }
    });
  });
});
// "последовательная" сортировка
$('.table__one thead td').not(':first-child').each(function(){
  $(this).click(function(e){
    e.preventDefault();
    $(this).parents('thead').find('td').removeClass('active');
    $(this).parents('thead').find('td').removeClass('taken');
    $(this).toggleClass('active');
    $(this).addClass('taken');
    let filter = $(this).attr('data-filter');
    console.log(filter)
    let filterArr = [];
    filterArr.push($(this).parents('table').find('tbody').find('tr[data-filter-' + filter + ' = "true"]'));
    $(this).parents('table').find('tbody').find('tr[data-filter-' + filter + ' = "true"]').remove();
    for(let i = 0; i < filterArr.length; i++) {
      $(this).parents('table').find('tbody').prepend(filterArr[i]);
      filterArr.pop(filterArr[i]);
    }
    let $tmpErt = $(this);
    $(this).parents('thead').find('td').not(':first-child').each(function(){
      if (!$(this).hasClass('taken')) {
        $tmpErt = $tmpErt.next();
        if ($tmpErt.length == 0) {
          $tmpErt = $(this).parents('thead').find('td:first-child').next();
        }
        let fil = $(this).parents('table').find('tbody').find('tr[data-filter-' + $tmpErt.attr('data-filter') + ' = "true"]');
        fil.remove();
        $(this).parents('table').find('tbody').append(fil);
        $(this).addClass('taken');
      }
    });
  });
});

Ну и самый сложный код, который уже просто с помощью sortElements не напишешь. В codepen можете увидеть, как именно он работает, на словах сложно точно сказать. Но сортирует "последовательно" каждый элемент).

Опущу объяснение про addClass и removeClass, тут в целом ничего такого. Единственное что важно - наличие класса taken. Он нам еще понадобится далее.

А вот дальше объявляется пустой массив filterArr, в котором в будущем будут храниться отсортированные значения. Через метод push массива в этот массив вставляем все элементы, которые выбрали (переменная filter хранит значение номера фильтра, например two, а если data-filter-two="true" - загоняем в массив). А собственно data-filter-two - это одна из строк таблицы. Она и попадает в массив.

Сразу после этого эта же строка (которая уже в массиве), удаляется из таблицы.

Далее в цикле for пробегаем по массиву выбранных строк таблицы и через prepend вставляем их обратно в таблицу (именно сверху, поэтому prepend,а не append). Сразу за этим, естественно, вырезаем строку из массива, чтобы он не сохранял ненужные значения.

Далее методом each проходим по всем td внутри thead (собственно тем элементам, по которым жмем для сортировки), кроме первого (т.к. там идет сортировка по алфавиту). Смотрим, если у нажатого элемента еще нет класса taken - ищем следующий за текущим элемент. Далее в переменную fil заносим следующую строку за уже выбранной (и так будет по каждому клику).

После этого удаляем эту же строку и уже через append вставляем ее в таблицу снова. Таким образом, когда нажимаем на сортировку, то элемент через prepend попадает на самый верх (как нам и надо), а все остальные (через next и append) вставляются по очереди за отсортированным. Отсюда и происходит такой эффект последовательности.

Ну и конечно, там еще есть условие if ($tmpErt.length == 0) - это для того чтобы если столбцы таблицы закончились - мы перескакивали на начало.

По факту, в этом примере не используется sortElements, но тем не менее сортировка получается интересной.

Ну и вот пен:

 

 

Надеюсь, Вам было полезно. Увидимся в следующих статьях :)

Метки: , ,

Понравилось? Оцени!
12345 (Пока оценок нет)
Загрузка...

Добавить комментарий

Ваш e-mail не будет опубликован. Обязательные поля помечены *