使用JavaScript对HTML表进行排序

luk*_*ger 51 javascript sorting html-table

我正在使用表格排序解决方案(在JavaScript中),但我似乎找不到合适的解决方案.我只需要按字母顺序对每列进行排序.它不需要忽略任何代码或任何数字或使用货币.只需单击列标题即可从排序的z/za中切换它.

有谁知道这样一个非常简单的解决方案?

Nic*_*aly 86

只是重新考虑一个旧的解决方案,我想我会为它的5周年纪念日改头换面!

  • 普通的Javascript(ES6)
  • alpha和数字排序 - 升序和降序
  • 适用于Chrome,Firefox,Safari(以及IE11,见下文)

快速解释

  1. click向所有header(th)单元格添加一个事件......
    1. 对于当前table,找到所有行(除了第一行)...
    2. 根据单击列的值对行进行排序...
    3. 按新顺序将行插回到表中.

const getCellValue = (tr, idx) => tr.children[idx].innerText || tr.children[idx].textContent;

const comparer = (idx, asc) => (a, b) => ((v1, v2) => 
    v1 !== '' && v2 !== '' && !isNaN(v1) && !isNaN(v2) ? v1 - v2 : v1.toString().localeCompare(v2)
    )(getCellValue(asc ? a : b, idx), getCellValue(asc ? b : a, idx));

// do the work...
document.querySelectorAll('th').forEach(th => th.addEventListener('click', (() => {
    const table = th.closest('table');
    Array.from(table.querySelectorAll('tr:nth-child(n+2)'))
        .sort(comparer(Array.from(th.parentNode.children).indexOf(th), this.asc = !this.asc))
        .forEach(tr => table.appendChild(tr) );
})));
Run Code Online (Sandbox Code Playgroud)
table, th, td {
    border: 1px solid black;
}
th {
    cursor: pointer;
}
Run Code Online (Sandbox Code Playgroud)
<table>
    <tr><th>Country</th><th>Date</th><th>Size</th></tr>
    <tr><td>France</td><td>2001-01-01</td><td><i>25</i></td></tr>
    <tr><td><a href=#>spain</a></td><td><i>2005-05-05</i></td><td></td></tr>
    <tr><td><b>Lebanon</b></td><td><a href=#>2002-02-02</a></td><td><b>-17</b></td></tr>
    <tr><td><i>Argentina</i></td><td>2005-04-04</td><td><a href=#>100</a></td></tr>
    <tr><td>USA</td><td></td><td>-6</td></tr>
</table>
Run Code Online (Sandbox Code Playgroud)


IE11支持(非ES6)

如果你想支持IE11,你需要沟ES6语法和添加polyfills为Array.from,Element.closestclick.

var getCellValue = function(tr, idx){ return tr.children[idx].innerText || tr.children[idx].textContent; }

var comparer = function(idx, asc) { return function(a, b) { return function(v1, v2) {
        return v1 !== '' && v2 !== '' && !isNaN(v1) && !isNaN(v2) ? v1 - v2 : v1.toString().localeCompare(v2);
    }(getCellValue(asc ? a : b, idx), getCellValue(asc ? b : a, idx));
}};

// do the work...
Array.prototype.slice.call(document.querySelectorAll('th')).forEach(function(th) { th.addEventListener('click', function() {
        var table = th.parentNode
        while(table.tagName.toUpperCase() != 'TABLE') table = table.parentNode;
        Array.prototype.slice.call(table.querySelectorAll('tr:nth-child(n+2)'))
            .sort(comparer(Array.prototype.slice.call(th.parentNode.children).indexOf(th), this.asc = !this.asc))
            .forEach(function(tr) { table.appendChild(tr) });
    })
});
Run Code Online (Sandbox Code Playgroud)

  • 如果您的行位于 `&lt;tbody&gt;` 标记内并且此答案有效,请参阅此答案的[此调整](/sf/answers/3771628521/)。 (8认同)
  • 请注意,如果标题行包含在<thead>元素中,则语句th.parentNode.parentNode将失败.我建议使用"var table = th.closest('table');".请注意,Element.closest()似乎没有在IE11/Edge中实现. (7认同)
  • 像我这样的javascript对新手的评论,因为我已经失去了很多时间来理解为什么它对我不起作用.因此,如果您只是将此脚本放在<script>标记的html中,则不会发生任何事情.你需要将这个函数链接到某个事件,例如加载窗口:window.onload = function(){/*脚本来自这个答案*/}然后它工作正常! (6认同)
  • @NickGrealy 感谢优雅的代码!这个名称叫什么:`this.asc = !this.asc` (2认同)
  • 是否有处理 $ 或其他货币等前缀的解决方案? (2认同)
  • 这值得比它有更多的支持。 (2认同)
  • 很不错!我必须检查 https://developer.mozilla.org/en-US/docs/Web/API/Node/appendChild 以了解为什么 table.appendChild(tr) 不会使当前 tr 加倍。MDN 规定:“如果给定的子节点是对文档中现有节点的引用,appendChild() 将其从当前位置移动到新位置”。 (2认同)

Pau*_* S. 73

我编写了一些代码,它们会逐行对表进行排序,假设只有一行,<tbody>而单元格没有colspan.

function sortTable(table, col, reverse) {
    var tb = table.tBodies[0], // use `<tbody>` to ignore `<thead>` and `<tfoot>` rows
        tr = Array.prototype.slice.call(tb.rows, 0), // put rows into array
        i;
    reverse = -((+reverse) || -1);
    tr = tr.sort(function (a, b) { // sort rows
        return reverse // `-1 *` if want opposite order
            * (a.cells[col].textContent.trim() // using `.textContent.trim()` for test
                .localeCompare(b.cells[col].textContent.trim())
               );
    });
    for(i = 0; i < tr.length; ++i) tb.appendChild(tr[i]); // append each row in order
}
// sortTable(tableNode, columId, false);
Run Code Online (Sandbox Code Playgroud)

如果您不想做出上述假设,您需要考虑在每种情况下的行为方式.(例如,将所有内容放在一起<tbody>或将所有前面的colspan值相加,等等)

然后,您可以将其附加到每个表格,例如假设标题在 <thead>

function makeSortable(table) {
    var th = table.tHead, i;
    th && (th = th.rows[0]) && (th = th.cells);
    if (th) i = th.length;
    else return; // if no `<thead>` then do nothing
    while (--i >= 0) (function (i) {
        var dir = 1;
        th[i].addEventListener('click', function () {sortTable(table, i, (dir = 1 - dir))});
    }(i));
}

function makeAllSortable(parent) {
    parent = parent || document.body;
    var t = parent.getElementsByTagName('table'), i = t.length;
    while (--i >= 0) makeSortable(t[i]);
}
Run Code Online (Sandbox Code Playgroud)

然后调用makeAllSortable onload.


它在桌子上工作的示例小提琴.

  • 回答我自己,我在[MDN](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/localeCompare#Using_options)中找到了选项的用法,所以使用`数字:真实的一个,你会很好的数字,甚至在字符串内.将`.localeCompare(b.cells [col] .textContent.trim())`替换为`.localeCompare(b.cells [col] .textContent.trim(),undefined,{numeric:true})` (9认同)
  • 这个片段对我帮助很大,太棒了! (2认同)

jed*_*rds 10

Nick Grealy接受的答案很好,但是如果您的行位于<tbody>标签内(行未曾进行过排序,排序后的行最终位于tbody标签之外,则可能会失去格式),这有点奇怪。

这是一个简单的解决方法,但是:

只是改变:

document.querySelectorAll('th').forEach(th => th.addEventListener('click', (() => {
  const table = th.closest('table');
  Array.from(table.querySelectorAll('tr:nth-child(n+2)'))
    .sort(comparer(Array.from(th.parentNode.children).indexOf(th), this.asc = !this.asc))
    .forEach(tr => table.appendChild(tr) );
Run Code Online (Sandbox Code Playgroud)

至:

document.querySelectorAll('th').forEach(th => th.addEventListener('click', (() => {
  const table = th.closest('table');
  const tbody = table.querySelector('tbody');
  Array.from(tbody.querySelectorAll('tr'))
    .sort(comparer(Array.from(th.parentNode.children).indexOf(th), this.asc = !this.asc))
    .forEach(tr => tbody.appendChild(tr) );
Run Code Online (Sandbox Code Playgroud)

  • 非常好的修复!我遇到了问题,因为我的桌子有“&lt;tbody&gt;”,这解决了它 (3认同)

Ces*_*las 8

使用 :hover 箭头效果进行表格排序。只需将类添加到要排序的每列的元素.order<th>

\n

\r\n
\r\n
function table_sort() {\n  const styleSheet = document.createElement(\'style\')\n  styleSheet.innerHTML = `\n        .order-inactive span {\n            visibility:hidden;\n        }\n        .order-inactive:hover span {\n            visibility:visible;\n        }\n        .order-active span {\n            visibility: visible;\n        }\n    `\n  document.head.appendChild(styleSheet)\n\n  document.querySelectorAll(\'th.order\').forEach(th_elem => {\n    let asc = true\n    const span_elem = document.createElement(\'span\')\n    span_elem.style = "font-size:0.8rem; margin-left:0.5rem"\n    span_elem.innerHTML = "\xe2\x96\xbc"\n    th_elem.appendChild(span_elem)\n    th_elem.classList.add(\'order-inactive\')\n\n    const index = Array.from(th_elem.parentNode.children).indexOf(th_elem)\n    th_elem.addEventListener(\'click\', (e) => {\n      document.querySelectorAll(\'th.order\').forEach(elem => {\n        elem.classList.remove(\'order-active\')\n        elem.classList.add(\'order-inactive\')\n      })\n      th_elem.classList.remove(\'order-inactive\')\n      th_elem.classList.add(\'order-active\')\n\n      if (!asc) {\n        th_elem.querySelector(\'span\').innerHTML = \'\xe2\x96\xb2\'\n      } else {\n        th_elem.querySelector(\'span\').innerHTML = \'\xe2\x96\xbc\'\n      }\n      const arr = Array.from(th_elem.closest("table").querySelectorAll(\'tbody tr\'))\n      arr.sort((a, b) => {\n        const a_val = a.children[index].innerText\n        const b_val = b.children[index].innerText\n        return (asc) ? a_val.localeCompare(b_val) : b_val.localeCompare(a_val)\n      })\n      arr.forEach(elem => {\n        th_elem.closest("table").querySelector("tbody").appendChild(elem)\n      })\n      asc = !asc\n    })\n  })\n}\n\ntable_sort()
Run Code Online (Sandbox Code Playgroud)\r\n
<table>\n  <thead>\n    <tr>\n      <th class="order">Country</th>\n      <th class="order">Date</th>\n      <th class="order">Size</th>\n    </tr>\n  </thead>\n  <tbody>\n    <tr>\n      <td>France</td>\n      <td>2001-01-01</td>\n      <td><i>25</i></td>\n    </tr>\n    <tr>\n      <td><a href=#>spain</a></td>\n      <td><i>2005-05-05</i></td>\n      <td></td>\n    </tr>\n    <tr>\n      <td><b>Lebanon</b></td>\n      <td><a href=#>2002-02-02</a></td>\n      <td><b>-17</b></td>\n    </tr>\n    <tr>\n      <td><i>Argentina</i></td>\n      <td>2005-04-04</td>\n      <td><a href=#>100</a></td>\n    </tr>\n    <tr>\n      <td>USA</td>\n      <td></td>\n      <td>-6</td>\n    </tr>\n  </tbody>\n</table>
Run Code Online (Sandbox Code Playgroud)\r\n
\r\n
\r\n

\n


BLS*_*lly 7

它确实不仅仅是"排序",而且dataTables.net可以满足您的需求.我每天都使用它,并得到很好的支持和非常快(需要jQuery)

http://datatables.net/

DataTables是jQuery Javascript库的插件.它是一个高度灵活的工具,基于渐进增强的基础,它将为任何HTML表添加高级交互控件.

Google Visualizations是另一种选择,但需要对dataTables进行更多设置,但不需要任何特定的框架/库(除了google.visualizations):

http://code.google.com/apis/ajax/playground/?type=visualization#table

还有其他选择......特别是如果你正在使用其他JS框架之一.Dojo,Prototype等都有可用的"表增强"插件,它们至少提供表排序功能.许多提供更多,但我会重申...我还没有遇到像datatables.net一样强大和快速的一个.

  • @BLSully:http://listjs.com/怎么样?我读到数据表非常粗糙,在某些情况下拍摄小型鸟类的大典型 (4认同)

Afi*_*eri 6

我知道使用javascript对HTML表进行排序的最佳方法是使用以下函数.

只需将您要排序的表的ID和行上的列号传递给它.它假定您要排序的列是数字或其中包含数字,并且将执行正则表达式替换以获取数字本身(非常适用于货币和其中包含符号的其他数字).

function sortTable(table_id, sortColumn){
    var tableData = document.getElementById(table_id).getElementsByTagName('tbody').item(0);
    var rowData = tableData.getElementsByTagName('tr');            
    for(var i = 0; i < rowData.length - 1; i++){
        for(var j = 0; j < rowData.length - (i + 1); j++){
            if(Number(rowData.item(j).getElementsByTagName('td').item(sortColumn).innerHTML.replace(/[^0-9\.]+/g, "")) < Number(rowData.item(j+1).getElementsByTagName('td').item(sortColumn).innerHTML.replace(/[^0-9\.]+/g, ""))){
                tableData.insertBefore(rowData.item(j+1),rowData.item(j));
            }
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

使用示例:

$(function(){
    // pass the id and the <td> place you want to sort by (td counts from 0)
    sortTable('table_id', 3);
});
Run Code Online (Sandbox Code Playgroud)