请问有人知道这样一个非常简单的解决方案吗?
重新审视一个旧解决方案,我想为它的五周年庆典提供一次面貌更新!
th
)单元格添加click
事件...table
,查找所有行(除了第一行)...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) );
})));
table, th, td {
border: 1px solid black;
}
th {
cursor: pointer;
}
<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>
如果你想要支持IE11,你需要放弃ES6语法,并使用Array.from
和Element.closest
的替代方案。
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) });
})
});
为了简洁起见,我压缩了comparer()
函数。它有点复杂/难以阅读,因此在此再次展开/格式化/加注释。
// Returns a function responsible for sorting a specific column index
// (idx = columnIndex, asc = ascending order?).
var comparer = function(idx, asc) {
// This is used by the array.sort() function...
return function(a, b) {
// This is a transient function, that is called straight away.
// It allows passing in different order of args, based on
// the ascending/descending order.
return function(v1, v2) {
// sort based on a numeric or localeCompare, based on type...
return (v1 !== '' && v2 !== '' && !isNaN(v1) && !isNaN(v2))
? v1 - v2
: v1.toString().localeCompare(v2);
}(getCellValue(asc ? a : b, idx), getCellValue(asc ? b : a, idx));
}
};
我写了一些代码,可以按行对表格进行排序,假设只有一个<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);
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]);
}
然后在onload
事件上调用makeAllSortable
函数。
这是一个在表格上运行的示例fiddle。
addEventListener
失败(String.prototype.trim
也会失败)。为了尝试找出问题出在哪里,请按F12并查看_Console_中出现/过的错误。 - Paul S.numeric: true
选项即可在字符串中正确比较数字。将.localeCompare(b.cells[col].textContent.trim())
替换为.localeCompare(b.cells[col].textContent.trim(), undefined, {numeric: true})
即可。 - FlaNick Grealy's accepted answer 很好,但如果您的行在一个 <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) );
收件人:
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) );
<tbody>
,所以出现了问题,但这个修复解决了它。 - T-101function 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));
}
}
}
}
使用示例:
$(function(){
// pass the id and the <td> place you want to sort by (td counts from 0)
sortTable('table_id', 3);
});
sortTable('table_id', 3)
吗? - paynehttp://code.google.com/apis/ajax/playground/?type=visualization#table
如果您使用其他JavaScript框架,还有其他选项可供选择。Dojo、Prototype等都有可用的“表格增强”插件,可以提供至少表格排序功能。许多插件提供更多功能,但是我要重申一下... 我还没有遇到过像datatables.net这样功能强大且快速的插件。
使用:hover箭头效果进行表格排序。只需将类.order
添加到需要排序的每个列的<th>
元素中。
function table_sort() {
const styleSheet = document.createElement('style')
styleSheet.innerHTML = `
.order-inactive span {
visibility:hidden;
}
.order-inactive:hover span {
visibility:visible;
}
.order-active span {
visibility: visible;
}
`
document.head.appendChild(styleSheet)
document.querySelectorAll('th.order').forEach(th_elem => {
let asc = true
const span_elem = document.createElement('span')
span_elem.style = "font-size:0.8rem; margin-left:0.5rem"
span_elem.innerHTML = "▼"
th_elem.appendChild(span_elem)
th_elem.classList.add('order-inactive')
const index = Array.from(th_elem.parentNode.children).indexOf(th_elem)
th_elem.addEventListener('click', (e) => {
document.querySelectorAll('th.order').forEach(elem => {
elem.classList.remove('order-active')
elem.classList.add('order-inactive')
})
th_elem.classList.remove('order-inactive')
th_elem.classList.add('order-active')
if (!asc) {
th_elem.querySelector('span').innerHTML = '▲'
} else {
th_elem.querySelector('span').innerHTML = '▼'
}
const arr = Array.from(th_elem.closest("table").querySelectorAll('tbody tr'))
arr.sort((a, b) => {
const a_val = a.children[index].innerText
const b_val = b.children[index].innerText
return (asc) ? a_val.localeCompare(b_val) : b_val.localeCompare(a_val)
})
arr.forEach(elem => {
th_elem.closest("table").querySelector("tbody").appendChild(elem)
})
asc = !asc
})
})
}
table_sort()
<table>
<thead>
<tr>
<th class="order">Country</th>
<th class="order">Date</th>
<th class="order">Size</th>
</tr>
</thead>
<tbody>
<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>
</tbody>
</table>
const arr = Array.from(th_elem.closest("table").querySelectorAll('tbody tr')).slice(1)
- WinEunuuchs2Unixclosest
表格及其tbody是低效的。你应该将tbody
缓存到一个变量中。此外,你可以用单个replaceChildren
调用来替换循环中的appendChild
:tbody.replaceChildren(...arr)
。 - JukkaP这里是使用纯JavaScript的完整示例。用于排序的算法基本上是冒泡排序(BubbleSort)。这里有一个Fiddle。
<!DOCTYPE html>
<html lang="de">
<head>
<meta charset="UTF-8">
<script type="text/javascript">
function sort(ascending, columnClassName, tableId) {
var tbody = document.getElementById(tableId).getElementsByTagName(
"tbody")[0];
var rows = tbody.getElementsByTagName("tr");
var unsorted = true;
while (unsorted) {
unsorted = false
for (var r = 0; r < rows.length - 1; r++) {
var row = rows[r];
var nextRow = rows[r + 1];
var value = row.getElementsByClassName(columnClassName)[0].innerHTML;
var nextValue = nextRow.getElementsByClassName(columnClassName)[0].innerHTML;
value = value.replace(',', '.'); // in case a comma is used in float number
nextValue = nextValue.replace(',', '.');
if (!isNaN(value)) {
value = parseFloat(value);
nextValue = parseFloat(nextValue);
}
if (ascending ? value > nextValue : value < nextValue) {
tbody.insertBefore(nextRow, row);
unsorted = true;
}
}
}
};
</script>
</head>
<body>
<table id="content-table">
<thead>
<tr>
<th class="id">ID <a
href="javascript:sort(true, 'id', 'content-table');">asc</a> <a
href="javascript:sort(false, 'id', 'content-table');">des</a>
</th>
<th class="country">Country <a
href="javascript:sort(true, 'country', 'content-table');">asc</a> <a
href="javascript:sort(false, 'country', 'content-table');">des</a>
</th>
<th class="some-fact">Some fact <a
href="javascript:sort(true, 'some-fact', 'content-table');">asc</a>
<a href="javascript:sort(false, 'some-fact', 'content-table');">des</a>
<th>
</tr>
</thead>
<tbody>
<tr>
<td class="id">001</td>
<td class="country">Germany</td>
<td class="some-fact">16.405</td>
</tr>
<tr>
<td class="id">002</td>
<td class="country">France</td>
<td class="some-fact">10.625</td>
</tr>
<tr>
<td class="id">003</td>
<td class="country">UK</td>
<td class="some-fact">15.04</td>
</tr>
<tr>
<td class="id">004</td>
<td class="country">China</td>
<td class="some-fact">13.536</td>
</tr>
</tbody>
</table>
</body>
</html>
sort
函数。这是一种相当易于维护的结构,可以进行操作(例如:排序)。var DATA_TABLE = {
{name: 'George', lastname: 'Blarr', age:45},
{name: 'Bob', lastname: 'Arr', age: 20}
//...
};
function sortDataTable(arrayColNames, asc) { // if not asc, desc
for (var i=0;i<arrayColNames.length;i++) {
var columnName = arrayColNames[i];
DATA_TABLE = DATA_TABLE.sort(function(a,b){
if (asc) {
return (a[columnName] > b[columnName]) ? 1 : -1;
} else {
return (a[columnName] < b[columnName]) ? 1 : -1;
}
});
}
}
function updateHTMLTable() {
// update innerHTML / textContent according to DATA_TABLE
// Note: textContent for firefox, innerHTML for others
}
现在让我们想象一下,您需要按姓氏、名字,最后按年龄排序。
var orderAsc = true;
sortDataTable(['lastname', 'name', 'age'], orderAsc);
{name: 'Jack', lastname: 'Ahrl', age: 20},
{name: 'Jack', lastname: 'Ahrl', age: 22},
//...
按单元格排序表格行。 1. 更简单,而且有一些功能。 2. 在排序时区分“数字”和“字符串”。 3. 添加切换以按升序或降序排序。
var index; // cell index
var toggleBool; // sorting asc, desc
function sorting(tbody, index){
this.index = index;
if(toggleBool){
toggleBool = false;
}else{
toggleBool = true;
}
var datas= new Array();
var tbodyLength = tbody.rows.length;
for(var i=0; i<tbodyLength; i++){
datas[i] = tbody.rows[i];
}
// sort by cell[index]
datas.sort(compareCells);
for(var i=0; i<tbody.rows.length; i++){
// rearrange table rows by sorted rows
tbody.appendChild(datas[i]);
}
}
function compareCells(a,b) {
var aVal = a.cells[index].innerText;
var bVal = b.cells[index].innerText;
aVal = aVal.replace(/\,/g, '');
bVal = bVal.replace(/\,/g, '');
if(toggleBool){
var temp = aVal;
aVal = bVal;
bVal = temp;
}
if(aVal.match(/^[0-9]+$/) && bVal.match(/^[0-9]+$/)){
return parseFloat(aVal) - parseFloat(bVal);
}
else{
if (aVal < bVal){
return -1;
}else if (aVal > bVal){
return 1;
}else{
return 0;
}
}
}
以下是HTML示例
<table summary="Pioneer">
<thead>
<tr>
<th scope="col" onclick="sorting(tbody01, 0)">No.</th>
<th scope="col" onclick="sorting(tbody01, 1)">Name</th>
<th scope="col" onclick="sorting(tbody01, 2)">Belong</th>
<th scope="col" onclick="sorting(tbody01, 3)">Current Networth</th>
<th scope="col" onclick="sorting(tbody01, 4)">BirthDay</th>
<th scope="col" onclick="sorting(tbody01, 5)">Just Number</th>
</tr>
</thead>
<tbody id="tbody01">
<tr>
<td>1</td>
<td>Gwanshic Yi</td>
<td>Gwanshic Home</td>
<td>120000</td>
<td>1982-03-20</td>
<td>124,124,523</td>
</tr>
<tr>
<td>2</td>
<td>Steve Jobs</td>
<td>Apple</td>
<td>19000000000</td>
<td>1955-02-24</td>
<td>194,523</td>
</tr>
<tr>
<td>3</td>
<td>Bill Gates</td>
<td>MicroSoft</td>
<td>84300000000</td>
<td>1955-10-28</td>
<td>1,524,124,523</td>
</tr>
<tr>
<td>4</td>
<td>Larry Page</td>
<td>Google</td>
<td>39100000000</td>
<td>1973-03-26</td>
<td>11,124,523</td>
</tr>
</tbody>
</table>
另一个简洁但易读的解决方案:
只需要将类.order
添加到每个要排序的列的<th>
元素中。
document.querySelectorAll('th.order').forEach(th_elem => {
let asc=true
const index = Array.from(th_elem.parentNode.children).indexOf(th_elem)
th_elem.addEventListener('click', (e) => {
const arr = [... th_elem.closest("table").querySelectorAll('tbody tr')]
arr.sort( (a, b) => {
const a_val = a.children[index].innerText
const b_val = b.children[index].innerText
return (asc) ? a_val.localeCompare(b_val) : b_val.localeCompare(a_val)
})
arr.forEach(elem => {
th_elem.closest("table").querySelector("tbody").appendChild(elem)
})
asc = !asc
})
})
this.asc = !this.asc
- krolovolk<tbody>
标签内,而这个答案无法正常工作,请参考这个微调。 - jedwards