Сортировка таблицы на jquery без плагинов

Встала задача отсортировать таблицу на яваскрипте по любому столбику. Известный всем плагин tablesorter у меня не заработал, и я решил, что быстрее и удобнее будет написать свой скрипт. Вот, что получилось через час:

Прямая и обратная сортировка таблицы по разным столбикамПрямая и обратная сортировка таблицы по разным столбикам

Демо

Скрипт получился из 20 строк, 1 кб (готовый tablesorter весит 13 кб и дольше «усваивается»). Ещё одно отличие: подготовительные операции для сортировки происходят по клику; это имеет смысл, потому что сортировка нужна не всем.

Первым делом нужно присвоить идентификаторы каждой строчке таблицы. Это лучше сделать сразу на сервере при выводе таблицы:

<tr id="z_1" ><td> ... </td></tr>
<tr id="z_2" ><td> ... </td></tr>
...

Теперь идентификатор будет привязан к строке с данными, и если её переставить в другое место, ничего не перепутается.

Сортировка массива

В интернете можно найти решения, где таблица целиком переводится в многомерный массив, а затем этот массив сортируется, после чего формируется и выводится новая таблица на место старой. Однако мне этот способ показался слишком громоздким, ведь достаточно держать в памяти всего два столбика:
1) по которому происходит сортировка,
2) столбик идентификаторов.

Можно обойтись простым массивом (ключ => значение), где ключ отвечает за номер строки. Но лично мне проще использовать двумерный массив, чтобы не запутаться между ключами и значениями.

На примере моей таблицы:

Кликаем по Площади — создаётся соответствующий двумерный массивКликаем по Площади — создаётся соответствующий двумерный массив
Сортируем массив по второму значениюСортируем массив по второму значению

А первые значения массива указывают, в каком порядке будут идти строки отсортированной таблицы.

Кстати, данный метод аналогичен сортировке в MySQL с использованием вре́менных таблиц.

Во временный массив желательно класть подготовленные значения, которые быстро и легко сравнивать. Лишнее (тэги и css) надо отбросить, отформатированные числа перевести в обычные числа (20 000 → 20000), а строки можно превратить в некие эквиваленты. Например, в моём случае единственный текстовый столбик содержит только два слова: свободен и бронь. У них разная длина, а значит, во временный массив можно записать только длину слов — этого хватит для корректного сравнения.

var z=$(this).children("td").eq(i_s).html().split(" ").join("");  //убираем пробелы
if(isFinite(z)) {z=parseInt(z);} else {z=z.length;} //число остаётся числом, а у строк оставляем только длину

В яваскрипте есть готовый алгоритм сортировки, использующий функцию сравнения двух элементов:

function sName(a,b) { //задаём функцию сравнения
if(a[0] < b[0]) {return (-1)*s_vozr;}
else if(a[0] > b[0]) {return s_vozr;}
else {return 0;}
}

multi.sort(sName); //сортируем массив multi, указав функцию sName

Функция sName(a,b) возвращает −1, 0 или 1. Если умножить возвращаемое значение на −1, то это изменит направление сортировки (по возрастанию или по убыванию). Таким образом, при помощи параметра s_vozr можно управлять направлением сортировки (если повторно кликнули по столбцу, параметр s_vozr меняет знак).

Перестановка строк таблицы

Теперь надо как-то удалить старую таблицу и показать новую, отсортированную. Тесты я не проводил (буду благодарен за ссылки в комментариях), но почти уверен, что экономичнее перемещать небольшие кусочки данных (то есть строки), чем парсить заново всю таблицу. Если это и не оптимизировано сейчас, то в будущем перемещение элементов должно занимать меньше времени, чем удаление старых и обработка новых элементов; а в нашем случае речь идёт о вставке довольно большой таблицы.

Как переделать старую таблицу в новую, используя перемещение строк? Пройдёмся в цикле по нашему вре́менному массиву, перемещая нужные строчки таблицы в её конец.

От того, куда перемещать строки — в конец или в начало — очевидно, зависит получаемое направление сортировки. Но эффективнее их сдвигать именно в конец. А если нужно изменить направление сортировки, то лучше пройтись по массиву в обратную сторону (или изначально сформировать обратный массив).

Перемещение строки c нужным id в конец таблицы (jquery):

$("#id_строки").appendTo($("#id_таблицы"));

Если бы мы хотели удалить строку, а затем поставить её в конец таблицы, то код выглядел бы так:

$("#id_строки").detach().appendTo($("#id_таблицы"));

Я не разбираюсь, как jquery использует ресурсы; но скорее всего, лучше перемещать без предварительного удаления.

4 мая 2013javascript

Заметка понравилась? → Поделитесь в соцсетях:

6 комментариев
Равиль
У вас ошибка в функции
должно быть
function sName(a,b) { if(a[1] < b[1]) {return (-1)*s_vozr;} else if(a[1]> b[1]) {return s_vozr;} else {return 0;} }
Ваня
Равиль, создаётся такой массив:
multi.push([z,$(this).attr("id")]);
z — первое значение — по нему должна идти сортировка, поэтому a[0] сравнивается с b[0]
Иван
Добрый день!
сделал вывод чисел через number format, и соответственно в таблице они сортируются неправильно. У вас все работает с вашим скриптом, вы как я понял преобразуете обратно в обычное число (сумму, площадь), можно ли показать, выслать исходники. Спасибо
Ваня
Исходный скрипт: http://gbip.ru/js/ceny.js (с 44-й строчки)
У меня при нажатии кнопки все ячейки столбца преобразуются в некие эквиваленты. Если это числа, то в числа, если это не числа, то в длину строки. Вот эта функция:
if(isFinite(z)) {z=parseInt(z);} else {z=z.length;}
lutskboy
Поправьте пожалуйста демо
Не работает
Ваня
То демо теперь под паролем, поэтому перенёс его к себе на сайт и упростил:
plunix.ru/w/sortirovka
(обновите)

Ваш комментарий

comments powered by HyperComments

Следующая заметка

Иван ТитовИван Титов
Фрилансер, музыкант, физтех по жизни, семьянин, философ.
© 2013