Сортировка таблицы быстро по ее первому столбцу с помощью Javascript или jQuery
У меня есть таблица, которая динамически заполняется из FullCalendar
.
Проблема в том, что FullCalendar
не заботится о своем первоначальном порядке.
Таблица выглядит так:
<table id="caltbl">
<thead>
<tr> <th> </th> <th> Date </th> <th> hours </th> ... </tr>
</thead>
<tbody>
<tr> <td class="sortnr">1</td> <td></td> ... </tr>
<tr> <td class="sortnr">3</td> <td></td> ... </tr>
<tr> <td class="sortnr">2</td> <td></td> ... </tr>
<tr> <td class="sortnr">4</td> <td></td> ... </tr>
</tbody>
</table>
Первая из каждой строки содержит номер, на котором должна быть отсортирована таблица.
У меня был этот код для его сортировки:
var rows = $('#caltbl > tbody').children('tr').detach();
for (var counter = 1; counter<=rows.length; counter++) {
$(rows).each(function(index) {
if ($(this).find(".sortnr").text()==counter){
$('#caltbl > tbody:last').append($(this));
}
});
}
Это отлично работает в Firefox, но вызывает у меня серьезную головную боль в Internet Explorer, потому что есть более 500 наименований и зависает. Я мог бы добавить setTimeout
, но это не решило бы настоящую проблему. Сортировка выполняется медленно. Что такое более быстрый способ сортировки этого?
Вместо того, чтобы начинать с <table>
html, как я уже сказал, он заполняется динамически, поэтому у меня есть Array
, который содержит html. 1 элемент за <tr>
(несортированный)
Ответы
Ответ 1
Fiddle: http://jsfiddle.net/qNwDe/
Я написал эффективный кросс-браузерный метод для сортировки строк в таблице. Несколько селекторов JQuery в двойных циклах вызывают серьезные проблемы с производительностью (как вы заметили), поэтому я избавился от JQuery.
Дополнительным преимуществом моей функции является то, что она не имеет против отсутствующих номеров индексов. В настоящее время я ссылаюсь на первую ячейку каждой строки, а не на получение элемента по имени класса. Если вы хотите ссылаться на имя класса, я изменю свою функцию:
function sortTable(){
var tbl = document.getElementById("caltbl").tBodies[0];
var store = [];
for(var i=0, len=tbl.rows.length; i<len; i++){
var row = tbl.rows[i];
var sortnr = parseFloat(row.cells[0].textContent || row.cells[0].innerText);
if(!isNaN(sortnr)) store.push([sortnr, row]);
}
store.sort(function(x,y){
return x[0] - y[0];
});
for(var i=0, len=store.length; i<len; i++){
tbl.appendChild(store[i][1]);
}
store = null;
}
Вызовите sortTable()
, когда хотите сортировать таблицу.
Ответ 2
Я думаю, что в вашем случае слишком много циклов. С 500 наименованиями вы будете использовать цикл 500 * 500 = 250000 раз. Не так много браузеров знали бы, как это сделать.
Я предлагаю использовать встроенный метод array.sort()
javascript для сортировки на основе пользовательской "функции сравнения".
Вот как это можно сделать (и, скорее всего, его можно оптимизировать): http://jsfiddle.net/tsimbalar/Dw6QE/.
Идея состоит в сортировке списка строк, сравнивающих значение sortNumber...
Ответ 3
Попробуйте такой подход:
http://jsfiddle.net/qh6JE/
var rows = $('#caltbl > tbody').children('tr').get(); // creates a JS array of DOM elements
rows.sort(function(a, b) { // use a custom sort function
var anum = parseInt($(a).find(".sortnr").text(), 10);
var bnum = parseInt($(b).find(".sortnr").text(), 10);
return anum-bnum;
});
for (var i = 0; i < rows.length; i++) { // .append() will move them for you
$('#caltbl > tbody').append(rows[i]);
}
Ответ 4
Проверьте http://square.github.com/crossfilter/, команда на Square использовала умный метод индекса растрового изображения, чтобы разрешить фильтрацию данных 5.3MB в < 30ms... Я не уверен, что это помогает, но это очень интересная техника.
Ответ 5
Мы можем использовать jquery insead javascript для той же самой вещи, на которую отвечает Rob W. Это не повлияет на любую проблему производительности, например, несколько селекторов JQuery в двойных циклах.
var $tbody = $('table tbody');
$tbody.find('tr').sort(function (a, b) {
var tda = $(a).find('td:eq(' + ColumnIndex + ')').text(); // Use your wished column index
var tdb = $(b).find('td:eq(' + ColumnIndex + ')').text(); // Use your wished column index
// if a < b return 1
return tda > tdb ? 1
// else if a > b return -1
: tda < tdb ? -1
// else they are equal - return 0
: 0;
}).appendTo($tbody);