【问题标题】:Javascript sort table column on click单击时的Javascript排序表列
【发布时间】:2019-08-23 01:30:31
【问题描述】:

我的意图是在单击th 时按升序对表格列(仅单击的列)进行排序。在进一步单击时,确切的表格列应按降序排列。

到目前为止我得到了什么:
表格正在排序,但单击时所有三列都在排序 - 我只希望对一列进行排序。

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>

【问题讨论】:

  • 一些改进问题的建议:您应该清楚您期望代码做什么,以及它实际做什么。您还应该解释您认为问题所在以及原因。理想情况下,使示例代码可运行。
  • @AlexMA 我已经更新了帖子,谢谢。

标签: javascript html


【解决方案1】:

这看起来也太夸张了。如果您只想对行进行排序,那么代码只需几行:

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));
}

神奇的部分起作用了,因为 DOM 节点只能存在于一个地方,所以如果你将它appendChild 到某个地方,它就会从最初所在的地方移动。因此,我们在 JS 中排序,然后按排序顺序运行appendChild,每一行都简单地从“无论它在哪里”移动到“子列表的末尾”,这意味着在我们运行完每一行之后rows,presto:现在所有行都根据需要重新排序。

当然,您仍然需要自己编写compareValues(a,b)。我不知道你想在那里做什么,因为也许你想要自然文本比较,或者你想要“如果值是数字,则作为数字比较,只有当它们不作为文本比较时”等等。

但您应该做的一件事是不要使用 1998 事件处理。不要使用onclick,在 JS 端正确执行此操作。所以在你的 HTML 中:

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

然后在JS端:

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

(更好的是,使用&lt;th&gt;&lt;button&gt;Nummer&lt;/button&gt;&lt;/th&gt; 并添加基于th button 的事件侦听器,因为就是这样。如果您有可以单击“做某事”的文本,那就是一个按钮。使用正确的标记,然后只需使用 CSS 设置您想要的样式,例如无边框、背景:继承等)

【讨论】:

  • 非常感谢!我是 JavaScript 新手——你告诉我不要使用旧的事件处理,并向我展示了一个替代方案。但是我在哪里同时使用函数和 eventListener,我如何在我的 .js 文件中安排它们(因为控制台告诉我 table 没有定义)?
  • 通常你给id属性的任何东西都会神奇地变成JS端直接可用的变量,但如果不是这样,你可以把let table = document.getElementById('table')放在最明智的“最高level”,以便您可以直接在您的函数中使用它。你把函数放在哪里几乎总是无关紧要的:在真正运行你的代码之前,JS 通过在 first 中读取所有函数来“提升”函数。 JS 中记录较少的特性之一,但却是一个非常重要的特性。
  • 我收到另一个错误:Failed to execute 'querySelector' on 'Element': 'td:nth-child(undefined' is not a valid selector.,此外,我应该在哪里放置一个挂钩来比较这些值?
  • 这看起来像是一个非常明显的错误? colnum 变量,我们知道它应该是一个数字,在错误消息中显示为 undefined,所以也许你忘记传递它 - 看看你在哪里添加事件监听器,并确保您正在将 th 的位置传递给对sortTable 的调用。至于比较函数,它只需要存在于sortTable 函数范围内的任何地方,因此显而易见的选择是“高于或低于它”。我已经用存根更新了答案。
【解决方案2】:

运行您的代码时,我得到了预期的结果。我想知道结果是否看起来不正确只是因为您的数据是这样设置的。

例如,您的数据是:

1   Deutschland Aaron
2   Rumänien    Dan
3   USA Peter

如果按数字排序,Aaron 将是 Deutschland First,并且 Deutschland 和 Aaron 在其余数据之前按字母顺序排在第一位。

因此,其他列正在排序是一种错觉,而实际上它们实际上只是遵循您的数据结构。

【讨论】:

    【解决方案3】:

    也许使用不同的方法。存储数据并在渲染前对数组进行排序。

    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>

    【讨论】:

    • 没必要,appendChild 可以很容易地在 JS 中对 HTML 元素进行排序,然后使用 forEach 在 DOM 中进行重新排序。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-08-27
    • 2019-10-01
    • 2013-07-06
    • 2020-05-25
    • 2019-04-05
    • 1970-01-01
    相关资源
    最近更新 更多