Pull to refresh

Comments 17

Если бы вы пользовались jQuery, то есть неплохой плагин tablesorter.com/docs/
Но спасибо за реализацию на чистом JS
Спасибо за плагин. На тот момент с jQuery не приходилось работать.
UFO just landed and posted this here
На момент написания скрипта много гуглил. Что-то было реализовано, что сам доходил. Конкретно данную ссылку не использовал.
Да, была ошибка. Спасибо, исправил. Копипаст — такой копипаст.
Намного оптимальней будет хранить данные со ссылкой на строку в таблице отдельно от представления, тогда не придется доставать данные из DOM для сортировки.
А можно несколько подробнее?
Человек предлагает, один раз создать массив из 100500 данных таблицы, где одно из значений будет ссылкой на DOM элемент таблицы. После сортировки надо будет пробежаться по этим ссылкам и расставить DOM элементы (в данным случае это TR) в порядке сортировки.

Как вариант, чтоб не захламлять память, можно в этом массиве данные заменить цифрами в порядке сортировки.
Пример:

было — ['Брест', 'Абакан', 'Воркута']
стало — [2,1,3]

А потом это уже сортировать легко и быстро.
Понятно. Вообще сначала так и хотел, 1 раз взять в данные из таблицы и больше их не вытаскивать, а просто показывать в нужном порядке. Проблему, с которой тогда столкнулся, не помню, и сделал в таком варианте.
Вариант с заменой на цифры тоже достоин внимания.
Несколько замечаний по коду:
1. TableSort имеет слишком много параметров, смысл которых сразу из вызывающего кода и не разберёшь
Лучше так
new TableSort({
    idTbl: 'idTbl',
    defSortCol: 0,
    firstRow: 1,
    needClasses: ['add', 'edd'],
    listClasses: ['odd', '']
});

2. Много переменных с глобальной областью видимости, хотя по замыслу их область видимости должна ограничиваться функцией TableSort. Как результат, код не будет работать в strict mode.
3. Не создавайте массивы, используя конструктор. Скорей всего Ваши коллеги будут подражать Вам и рано или поздно потратят много эмоций, чтобы понять, что
var arr = new Array(10);
и
var arr = [10];
— совсем не одно и то же.
Спасибо, нет предела совершенству. Думаю в дальнейшем использовать jQuery и необходимый плагин.
Спасибо что написали плагин.
Таких как вы становится все меньше.

plugindetector.com/category/tables

Tablesorter конечно более надежен и многофункционален.
И вообще поддержка и развитие это очень серьезная задача.
Гораздо более серьезная чем первоначальное написание.
Приведенный способ среди всех, которые я видел, является средним (как по быстродействию, так и по сложности реализации). Действительно хорошим советом является отделение данных от DOM (KAdot). Это увеличит скорость.
Как-нибудь напишу статьи про:
1) построение HTML с помощью JS;
2) сортировку данных в таблицах.
Автору плюсик за старание.
Ваше решение, мягко говоря, не оптимально и годится для примера того «как делать не надо».
Обратим внимание на некоторые части вашего решения.
1. Для отделения мух от котлет в таблицах используются секции thead, tbody, tfoot. Если вы вынесете ваш заголовок (строку с th) в thead, вам не нужно будет задавать firstRow. В будущем вы можете добавить еще и tfoot для подвала. Секций tbody может быть несколько и видимо сортировать нужно в каждой секции отдельно (если конечно ваша логика вашего алгоритма не предусматривает иного).
2. Вы делаете очень накладные выборки и не кешируете их. Например:
   for (j=0; j<allTrs[i].getElementsByTagName('td').length; j++) {
       tblData[i-numColTr][j] = allTrs[i].getElementsByTagName('td').item(j).innerHTML;
   }

Этот код будет работать безумно долго, так как для строки вы N^2 раз выбираете все ячейки. То есть браузер перебирает N^2 DOM там где достаточно одного раза. Так же не забываем, что getElementsByTagName возвращает не массив, а коллекцию и обращение к length приводит к вычитыванию размерности этой коллекции. Об этом пишут практически в любом мануале по работе с DOM. Оптимальным (в плане работы с DOM) будет вариант:
   var cells = allTrs[i].getElementsByTagName('td');
   for (j = 0, cell; cell = cells[j]; j++) {
      tblData[i-numColTr][j] = cell.innerHTML;
   }

3. Вот скажите, зачем вы таскаете html ячеек? Сначала вы нагружаете браузер когда перебираете ячейки, потом когда считываете innerHTML (он вычисляется), потом опять перебираете, и присваиваете html другой ячейке, заставляя браузер парсить этот html, а заканчиваете переносом классов. Почему нельзя перемещать строки?
Вся сортировка сводится к
var allTrs = tbl.tBodies[0].getElementsByTagName('tr');

...

this.initSort = function (newCol, normalize) {
  if (newCol == curSortCol)
  {
    curSortUp = !curSortUp;
  }
  else
  {
    curSortUp = true;
    curSortCol = newCol;
  }

  // вычисляем значение для сортировки
  for (var i = 0, row; row = allTrs[i]; i++)
    row.sortValue = normalize(row.childNodes[columnNum].innerHTML);

  // сортируем
  allTrs.sort(function(a, b){
    return (a.sortValue > b.sortValue) || -(a.sortValue < b.sortValue);
  });

  if (!curSortUp)
    allTrs.reverse();

  // выставляем ряды в нужном порядке
  for (var i = allTrs.length - 1, row, last = null; row = allTrs[i]; i--)
  {
    row.parentNode.insertBefore(row, last);

    // тут можно сделать что-то с чередующимися классами

    last = row;
  }

Вот и все — функции getDataTable, _sort, showSortTable, doStyle можете удалить.
4. Кстати об initSort, она должна принимать номер колонки и функцию нормализации. По данным в html нельзя определить что за тип — это строка, число, дата или еще что. То есть нужно передавать:
  initSort(1, Number); // для числовой сортировки
  initSort(1, String);    // для строковой
  initSort(1, function(value){ return value.toLowerCase() }) // для строковой без учета регистра
  initSort(1, function(value){ return +new Date(value) }) // для сортировки дат
      // но здесь value должно быть определенного формата, либо же пишется функция разбора даты..
      // даты лучше сортировать как числа
      // в любом случае вы вольны определить значение для сортировки так как нужно,
      // автоматически это сделать не получится

  // Типовые сортировки можно сохранить в константы
  TableSort.prototype.SORT_DATE = function(value){ return +new Date(value) };
  ...
  table.initSort(1, table.SORT_DATE);

5. Этот код не правильно отсортирует если в таблице будут отрицательные числа
    function _sort(a1, b1) {
       ...
        if (parseFloat(a) && parseFloat(b)) {
            return parseFloat(a) - parseFloat(b);
       ...

6. Вместо добавления изображений в заголовки, лучше добавлять/удалять класс, а стили, в том числе и изображения, задавать через css.
7. Чередующиеся классы не является обязательным атрибутом таблицы, потому можно воспользоваться правилами :nth-child(2n) или :nth-child(2n + 1) чтобы раскрасить таблицу в зебру.
  tr:nth-child(2n)
  {
    background: gray;
  }

В старых браузерах не будет зебры, но это не фатально, к тому же таких браузеров все меньше с каждым. Зато код будет меньше и чище и лучше стилизоваться через css.

В итоге ваша инициализация сортировки, если применить все рекомендации, будет выглядеть так:
  var infoTblSort = new TableSort("idTbl", 0);

И кода в разы меньше.

Удачи.
Sign up to leave a comment.

Articles