web-dev-qa-db-ja.com

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では正常に機能しますが、500を超えるアイテムがありハングするため、Internet Explorerで大きな頭痛の種になります。 setTimeoutを追加することはできますが、実際の問題は解決しません。 ソートが遅い。これをソートするより速い方法は何ですか?

<table> htmlから開始する代わりに、動的に入力されるので、htmlを含むArrayがあります。 <tr>あたり1アイテム(未ソート)

23
Stefanvds

フィドル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()を呼び出してください。

51
Rob W

次のようなアプローチを試してください。 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]);
}
7
Blazemonger

あなたの場合、ループが多すぎると思います。 500アイテムの場合、500 * 500 = 250000回ループします。それほど多くのブラウザはそれを行う方法を知っていません。

ネイティブの array.sort() javascriptのメソッドを使用して、カスタムの「比較関数」に基づいてソートを行うことをお勧めします。

これがどのように行われる可能性があるか(そしておそらく最も最適化できる): http://jsfiddle.net/tsimbalar/Dw6QE/

アイデアは、sortNumber値を比較する行のリストをソートすることです...

5
tsimbalar

これを確認してください http://square.github.com/crossfilter/ Squareのチームは、賢いビットマップインデックス手法を使用して、<30msで5.3MBデータをフィルタリングできるようにしています...これが役立つかどうかはわかりませんが、非常に興味深いテクニックです

1
Deano

Rob Wが答えたのと同じことに対して、javascriptのjqueryを使用できます。ダブルループの複数の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);

降順では>の代わりに<を使用します。

[〜#〜] fiddle [〜#〜]

1
SharmaPattar