简体   繁体   English

单击时的Javascript排序表列

[英]Javascript sort table column on click

My intention is to sort a table column (only the clicked th's column) in ascending order when th is being clicked.我的意图是在单击th时按升序对表列(仅单击的列)进行排序。 On further click the exact table column shall be ordered in a descending order.在进一步单击时,确切的表格列应按降序排列。

What I got so far:到目前为止我得到了什么:
The table is being sorted, but on click all three columns are being sorted - I only want one column to be sorted.表格正在排序,但单击时所有三列都在排序 - 我只希望对一列进行排序。

 function sortTable(n) { var table, rows, switching, i, x, y, shouldSwitch, dir, switchcount = 0; table = document.getElementById("table"); switching = true; dir = "asc"; while (switching) { switching = false; rows = table.rows; for (i = 1; i < (rows.length - 1); i++) { shouldSwitch = false; x = rows[i].getElementsByTagName("TD")[n]; y = rows[i + 1].getElementsByTagName("TD")[n]; if (dir == "asc") { if (x.innerHTML.toLowerCase() > y.innerHTML.toLowerCase()) { shouldSwitch = true; break; } } else if (dir == "desc") { if (x.innerHTML.toLowerCase() < y.innerHTML.toLowerCase()) { shouldSwitch = true; break; } } } if (shouldSwitch) { rows[i].parentNode.insertBefore(rows[i + 1], rows[i]); switching = true; switchcount ++; } else { if (switchcount == 0 && dir == "asc") { dir = "desc"; switching = true; } } } }
 <table id="table"> <tr> <th onclick="sortTable(0)">Nummer</th> <th onclick="sortTable(1)">Land</th> <th onclick="sortTable(2)">Name</th> </tr> <tr> <td>2</td> <td>Rumänien</td> <td>Dan</td> </tr> <tr> <td>1</td> <td>Deutschland</td> <td>Aaron</td> </tr> <tr> <td>3</td> <td>USA</td> <td>Peter</td> </tr> </table>

This also looks like extreme overkill for the description.对于描述来说,这看起来也太过分了。 If all you want to do is sort your rows, then the code for that is a few lines:如果您只想对行进行排序,那么该代码是几行:

function compareValues(a, b) {
  // return -1/0/1 based on what you "know" a and b
  // are here. Numbers, text, some custom case-insensitive
  // and natural number ordering, etc. That's up to you.
  // A typical "do whatever JS would do" is:
  return (a<b) ? -1 : (a>b) ? 1 : 0;
}

function sortTable(colnum) {
  // get all the rows in this table:
  let rows = Array.from(table.querySelectorAll(`tr`));

  // but ignore the heading row:
  rows = rows.slice(1);

  // set up the queryselector for getting the indicated
  // column from a row, so we can compare using its value:
  let qs = `td:nth-child(${colnum})`;

  // and then just... sort the rows:
  rows.sort( (r1,r2) => {
    // get each row's relevant column
    let t1 = r1.querySelector(qs);
    let t2 = r2.querySelector(qs);

    // and then effect sorting by comparing their content:
    return compareValues(t1.textContent,t2.textContent);
  });

  // and then the magic part that makes the sorting appear on-page:
  rows.forEach(row => table.appendChild(row));
}

The magic part works because DOM nodes can only exist in one place, so if you appendChild it to something, it gets moved from wherever it was in the first place.神奇的部分作品,因为DOM节点可以在一个地方只存在,因此,如果您appendChild它的东西,它就会不管它是在第一个地方移动 As such, we sort in JS, and then we run appendChild in that sorted order, every row is simply moved from "whereever it was" to "the end of the child list", which means after we run through every row in rows , presto: all the rows are now reordered as needed.因此,我们的排序在JS,然后我们运行appendChild在有序,每一行仅仅是从移动“等。无论是”到,该装置后,我们通过每一行运行“孩子列表的末尾” rows , presto:现在根据需要重新排序所有行。

Of course you're still on the hook for writing compareValues(a,b) yourself.当然,您仍然需要自己编写compareValues(a,b) I don't know what you want to do there, because maybe you want natural text compare, or maybe you want "if the values are numbers, compare as numbers, only if they're not compare as text", etc.我不知道你想在那里做什么,因为也许你想要自然文本比较,或者你想要“如果值是数字,则作为数字进行比较,仅当它们不是作为文本进行比较时”等。

But one thing you should do is not use 1998 event handling.但是您应该做的一件事是不要使用 1998 事件处理。 Don't use onclick , do this properly on the JS side.不要使用onclick ,在 JS 端正确执行此操作。 So in your HTML:所以在你的 HTML 中:

<tr>
  <th>Nummer</th>
  <th>Land</th>
  <th>Name</th>
</tr>

And then on the JS side:然后在 JS 方面:

table.querySelectorAll(`th`).forEach((th, position) => {
  th.addEventListener(`click`, evt => sortTable(position));
});

(and better yet, use <th><button>Nummer</button></th> and add the event listener based on th button , because that's what it is. If you have text that can be clicked to "do something", that's a button. Use the correct markup, and then just use CSS to style it however you want, eg no border, background:inherit, etc) (更好的是,使用<th><button>Nummer</button></th>并添加基于th button的事件侦听th button ,因为它就是这样。如果您有可以单击以“做某事”的文本,那是一个按钮。使用正确的标记,然后只需使用 CSS 设置您想要的样式,例如无边框、背景:继承等)

Maybe use a different approach.也许使用不同的方法。 Store your data and sort the array before rendering.在渲染之前存储您的数据并对数组进行排序。

 let tblData = [{ number: 2, land: 'Rumänien', name: 'Dan' }, { number: 1, land: 'Deutschland', name: 'Aaron' }, { number: 3, land: 'USA', name: 'Peter' } ]; const getRow = (data) => `<tr><td>${data.number}</td><td>${data.land}</td><td>${data.name}</td></tr>`; const sortNumber = (a, b) => a.number - b.number; const sortLand = (a, b) => (a.land === b.land) ? 0 : (a.land > b.land) ? 1 : -1; const sortName = (a, b) => (a.name === b.name) ? 0 : (a.name > b.name) ? 1 : -1; function buildTable(data) { document.querySelector('tbody').innerHTML = data.map(row => getRow(row)).join(''); } function sortTable(n) { let sort = sortNumber; switch (n) { case 1: sort = sortLand; break; case 2: sort = sortName; } console.log(n); buildTable(tblData.sort(sort)); } buildTable(tblData);
 <table id="table"> <thead> <tr> <th onclick="sortTable(0)">Nummer</th> <th onclick="sortTable(1)">Land</th> <th onclick="sortTable(2)">Name</th> </tr> </thead> <tbody> </tbody> </table>

When running your code, I get the results that I would expect.运行您的代码时,我得到了预期的结果。 I wonder if it seems like the results aren't correct simply because your data is setup that way.我想知道是否仅仅因为您的数据是这样设置的,结果似乎不正确。

For example, your data is:例如,您的数据是:

1   Deutschland Aaron
2   Rumänien    Dan
3   USA Peter

And sorting on Number, would have Deutschland First with Aaron, and both Deutschland and Aaron are alphabetically first before the rest of the data.对 Number 进行排序,将有 Deutschland First 和 Aaron,并且 Deutschland 和 Aaron 在其余数据之前按字母顺序排在第一位。

So its an illusion that the other columns are being sorted, when in fact they are actually just following your data structure.因此,其他列正在排序是一种错觉,而实际上它们实际上只是遵循您的数据结构。

Mike 'Pomax' Kamermans ' answer works very well except the sorted table will place the <tr> s outside the <tbody> tag, which is undesired. Mike 'Pomax' Kamermans的回答效果很好,除了排序表会将<tr>放在<tbody>标记之外,这是不希望的。 This can be easily solved by changing his answer to this:这可以通过更改他的答案来轻松解决:

function sortTable(colnum) {
  let tbody = table.querySelector(`tbody`);
  let rows = Array.from(table.querySelectorAll(`tr`));
  
  // other codes...
  
  rows.forEach(row => tbody.appendChild(row));
  table.appendChild(tbody);
}

Then the generated table should be working perfectly.然后生成的表应该可以正常工作。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM