用JavaScript对HTML表格进行排序的最有效方法是什么?

6
我正在编写一些JS代码来排序HTML表格:HTML表格有一个标题行,点击列的标题将根据该列对行进行排序。我的通用算法如下:
  1. 将HTML转换为JavaScript数组。
  2. 对JavaScript数组进行排序。
  3. 重新将JavaScript数组转换为HTML表格。
目前,我的代码替换了表格的所有innerHTML元素。基本上,在它对JS数组进行排序之后,它会触及表的每个节点,重写它的innerHTML值。我感觉可能有更有效率的方法来完成这个任务,但我想不出来。
编辑:
以下是上述算法第(3)部分的代码。我删除了无关的部分(只是一些字符串变换)。索引有点奇怪,因为我在将表格转换为数组时跳过了标题行,所以在重写表格时要进行补偿。
for (var i = 0; i < numRows-1; i++){
 for (var j = 0; j < numCols; j++){
        var arrCell = tableArr[i][cols[j]];
        tableEl.rows[i+1].cells[j].innerHTML = arrCell;
    }
}

你想要仅使用纯JS实现这个吗? - Jeff Noel
只要您在内存中生成新的标记,然后通过仅使用1个DOM操作进行附加,这应该是相当高效的。DOM修改比Javascript数组操作慢得多。 - chrisfrancis27
@Ghillied 是的。我的意思是,除了纯JS之外,是否有更有效的方法来做到这一点?您是建议我将标题行转换为链接,并从服务器重新获取已排序的表格吗? - Son of the Wai-Pan
@ChrisFrancis 对于一个包含n个节点的表格,我正在执行n个DOM操作(即我正在重写innerHTML)。 - Son of the Wai-Pan
@Avery 除了使用纯JS外,没有更有效的方法来处理这个问题。我向您介绍了一个使用库的方法,但是使用库会为您的页面加载额外的千字节,而这些功能可能并不需要(因为您不会使用库中的其他函数)。 - Jeff Noel
@Avery 好的。如果您在内存中创建表格完整DOM元素树的表示,然后对其进行所有修改,最后替换表格本身的innerHTML,您应该会看到明显的性能提升。 - chrisfrancis27
4个回答

2
您可以从DOM中删除行,进行排序,然后将它们重新添加到DOM中。
var tbody = table.tBodies[0];

var placeholder = document.createElement('tbody');
table.replaceChild(placeholder, tbody);

//sort rows in tbody

table.replaceChild(tbody, placeholder);

我不知道为什么这个被踩了。从DOM中删除一个元素,对其进行大量更改(如排序移动元素),然后将其添加回DOM中会更快。这样可以减少页面重绘次数,而不是每次移动一行都要进行一次页面重绘。 - Nicholas

1
使用数组对值进行排序,并使用文档片段执行更新。
function sortRows(tbody, compare, sortDesc) {
    //convert html collection to array
    var rows = [].slice.call(tbody.rows);
    //sort to desired order
    rows.sort(compare);
    if (sortDesc) {
        rows.reverse();
    }
    //update table
    var fragment = document.createDocumentFragment();
    rows.forEach(function (row) {
        fragment.appendChild(row);
    });
    tbody.appendChild(fragment);
}

复杂性将在比较函数中体现。您需要考虑列索引以及任何类型转换和缓存。
这是一个基本示例,它将单元格文本内容转换为整数。

function sortTable(table, columnIndex) {
    while (table && table.tagName !== 'TABLE') {
        table = table.parentNode;
    }
    if (table) {
        sortRows(table.tBodies[0], function compare(topRow, bottomRow) {
            var topValue = parseInt(topRow.cells[columnIndex].textContent, 10);
            var bottomValue = parseInt(bottomRow.cells[columnIndex].textContent, 10);
            return (topValue - bottomValue);
        });
    }
}

function sortRows(tbody, compare, sortDesc) {
    //convert html collection to array
    var rows = [].slice.call(tbody.rows);
    //sort to desired order
    rows.sort(compare);
    if (sortDesc) {
        rows.reverse();
    }
    //update table
    var fragment = document.createDocumentFragment();
    rows.forEach(function (row) {
        fragment.appendChild(row);
    });
    tbody.appendChild(fragment);
}
<table>
    <thead>
        <tr><th onclick="sortTable(this, 0)">Sort</th><th onclick="sortTable(this, 1)">Sort</th></tr>
    </thead>
    <tbody>
        <tr><td>1</td><td>25</td></tr>
        <tr><td>3</td><td>12</td></tr>
        <tr><td>2</td><td>40</td></tr>
        <tr><td>10</td><td>25</td></tr>
    </tbody>
</table>


如果您需要使用IE8,则请使用跨浏览器的方法/属性替换[].slice.call(),rows.forEach()和cell.textContent。 - Nicholas

0
如果数据存储在服务器上 - 我会发送一个带有排序类型(ASC,DESC等)的Ajax请求到服务器,使用PHP等在服务器上对数据进行排序,然后在JavaScript中接收排序后的数据,并完全重新编写表格。

0
你可以使用jQuery和它的Datatables插件。在你的datatable语句中,你可以添加 < p > < code > "bSort": true

脚本将完成这项工作。虽然如果你能找到一个纯JS的方法,我建议你使用它,这样你就不会给你的网页增加无用的负担。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接