可以将文章内容翻译成中文,广告屏蔽插件可能会导致该功能失效(如失效,请关闭广告屏蔽插件后再试):
问题:
I'm after a table sorting solution (in JavaScript) but I can't seem to find a suitable one yet. I just need it to sort each column alphabetically. It doesn't need to ignore any code or any numbers or to work with currency. Just a click on the column header switches it from sorted a-z/z-a.
Does anyone know of a really simple solution like this?
回答1:
Just revisiting an old solution, I thought I'd give it a facelift for it's ~5 year anniversary!
- Plain Javascript (ES6)
- Does alpha and numeric sorting - ascending and descending
- Works in Chrome, Firefox, Safari (and IE11, see below)
Quick explanation
- add a
click
event to all header (th
) cells... - for the current
table
, find all rows (except the first)... - sort the rows, based on the value of the clicked column...
- insert the rows back into the table, in the new order.
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 Support (non-ES6)
If you want to support IE11, you'll need to ditch the ES6 syntax and add polyfills for Array.from
, Array.forEach
and Element.closest
.
i.e.
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.from(document.querySelectorAll('th')).forEach(function(th) { th.addEventListener('click', function() { var 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(function(tr) { table.appendChild(tr) }); }) });
回答2:
I wrote up some code that will sort a table by a row, assuming only one <tbody>
and cells don't have a 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);
If you don't want to make the assumptions above, you'd need to consider how you want to behave in each circumstance. (e.g. put everything into one <tbody>
or add up all the preceeding colspan values, etc.)
You could then attach this to each of your tables, e.g. assuming titles are in <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]); }
and then invoking makeAllSortable
onload.
Example fiddle of it working on a table.
回答3:
It does WAY more than "just sorting", but dataTables.net does what you need. I use it daily and is well supported and VERY fast (does require jQuery)
http://datatables.net/
DataTables is a plug-in for the jQuery Javascript library. It is a highly flexible tool, based upon the foundations of progressive enhancement, which will add advanced interaction controls to any HTML table.
Google Visualizations is another option, but requires a bit more setup that dataTables, but does NOT require any particular framework/library (other than google.visualizations):
http://code.google.com/apis/ajax/playground/?type=visualization#table
And there are other options to... especially if you're using one of the other JS frameworks. Dojo, Prototype, etc all have usable "table enhancement" plugins that provide at minimum table sorting functionality. Many provide more, but I'll restate...I've yet to come across one as powerful and as FAST as datatables.net.
回答4:
The best way I know to sort HTML table with javascript is with the following function.
Just pass to it the id of the table you'd like to sort and the column number on the row. it assumes that the column you are sorting is numeric or has numbers in it and will do regex replace to get the number itself (great for currencies and other numbers with symbols in it).
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)); } } } }
Using example:
$(function(){ // pass the id and the <td> place you want to sort by (td counts from 0) sortTable('table_id', 3); });
回答5:
You could deal with a json array and the sort
function. It is a pretty easy maintanable structure to manipulate (ex: sorting).
Untested, but here's the idea. That would support multiple ordering and sequential ordering if you pass in a array in which you put the columns in the order they should be ordered by.
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 }
Now let's imagine you need to order by lastname, then name, and finally by age.
var orderAsc = true; sortDataTable(['lastname', 'name', 'age'], orderAsc);
It should result in something like :
{name: 'Jack', lastname: 'Ahrl', age: 20}, {name: 'Jack', lastname: 'Ahrl', age: 22}, //...
回答6:
Here is a complete example using pure JavaScript. The algorithm used for sorting is basically BubbleSort. Here is a 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>
You can also check out the source from here: https://github.com/wmentzel/table-sort
回答7:
Sorting table rows by cell. 1. Little simpler and has some features. 2. Distinguish 'number' and 'string' on sorting 3. Add toggle to sort by ASC, DESC
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; } } }
below is html sample
<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>