【问题标题】:Merge neighbouring HTML table cells with same value using JS使用JS合并具有相同值的相邻HTML表格单元格
【发布时间】:2019-10-28 10:27:45
【问题描述】:

我已经为此苦苦挣扎了一段时间。我有一个根据一些 JSON 数据自动生成的表,这些数据可能会有所不同。我想合并第一列中具有相同值的相邻单元格,例如此表中的“鱼”和“鸟”:

<table>
  <tr>
    <td>fish</td>
    <td>salmon</td>
  </tr>
  <tr>
    <td>fish</td>
    <td>cod</td>
  </tr>
  <tr>
    <td>fish</td>
    <td>plaice</td>
  </tr>
  <tr>
    <td>bird</td>
    <td>robin</td>
  </tr>
  <tr>
    <td>bird</td>
    <td>crow</td>
  </tr>
</table>

理想情况下我不想使用任何库,只需要纯 JS。

这是我想要的样子:

table, tr, td {
  border: solid 1px black;
}
<table>
  <tr>
    <td rowspan="3">fish</td>
    <td>salmon</td>
  </tr>
  <tr>
    <td>cod</td>
  </tr>
  <tr>
    <td>plaice</td>
  </tr>
  <tr>
    <td rowspan="2">bird</td>
    <td>robin</td>
  </tr>
  <tr>
    <td>crow</td>
  </tr>
</table>

我一直在寻找不同的方法来识别不同的值及其频率,然后将行跨度更改为正确的数字,然后删除其他单元格,但这些都在不同的用例中崩溃了。

这是我目前所拥有的:

let table = document.querySelector('table');
let rowCount = 1;

for (let i = 0; i < (table.rows.length - 1); i++) {
  if (table.rows[i].cells[0].innerHTML === table.rows[i + 1].cells[0].innerHTML) {
    rowCount++;
  } else if (rowCount !== 1) {
    table.rows[i].cells[0].setAttribute('rowspan', rowCount);
    for (let j = (i - rowCount + 1); j < rowCount; j++) {
      table.rows[j].cells[0].remove();
    };
    rowCount = 1;
  };
};
table, tr, td {
  border: solid 1px black;
}
<table>
  <tr>
    <td>fish</td>
    <td>salmon</td>
  </tr>
  <tr>
    <td>fish</td>
    <td>cod</td>
  </tr>
  <tr>
    <td>fish</td>
    <td>plaice</td>
  </tr>
  <tr>
    <td>bird</td>
    <td>robin</td>
  </tr>
  <tr>
    <td>bird</td>
    <td>crow</td>
  </tr>
</table>

这根本不是我想要的,但我觉得我真的很接近了!它试图计算下面一个具有相同值的(第一列)单元格的数量,将此数字分配给最后一个相关单元格的行跨度,然后删除后续单元格,然后再循环返回以捕获其余单元格。我希望我的最终代码是这个的变体,所以有人可以告诉我我哪里出错了吗?非常感谢!

【问题讨论】:

  • 请与预期的表行分享示例场景
  • @NagaSaiA 谢谢 - 好点,现在添加到问题中(jsfiddle.net/5rdw6v4h)
  • 可能的旁注:那时你可能希望那些是&lt;th&gt;s(至少在简单示例中的上下文 - 我可能错了。)。

标签: javascript html html-table merge


【解决方案1】:

你确实很接近!

一种相当简化的方法是保留对当前“标题”单元格的引用,即您要增加rowspan 的那个。这样一来,您根本不必处理索引,从而产生一个非常简单的算法:

  • 对于每一行

    • 将firstCell设置为行的第一个单元格
    • 如果这是第一行或 firstCell 的文本与 headerCell 的文本不同

      • 将 headerCell 设置为 firstCell
    • 否则
      • 将 headerCell 的 rowSpan 增加 1
      • 删除 firstCell

在 JavaScript 中,它看起来像这样:

const table = document.querySelector('table');

let headerCell = null;

for (let row of table.rows) {
  const firstCell = row.cells[0];
  
  if (headerCell === null || firstCell.innerText !== headerCell.innerText) {
    headerCell = firstCell;
  } else {
    headerCell.rowSpan++;
    firstCell.remove();
  }
}
table, tr, td {
  border: solid 1px black;
}
<table>
  <tr>
    <td>fish</td>
    <td>salmon</td>
  </tr>
  <tr>
    <td>fish</td>
    <td>cod</td>
  </tr>
  <tr>
    <td>fish</td>
    <td>plaice</td>
  </tr>
  <tr>
    <td>bird</td>
    <td>robin</td>
  </tr>
  <tr>
    <td>bird</td>
    <td>crow</td>
  </tr>
</table>

【讨论】:

  • 非常感谢,这是一个非常优雅的解决方案。我现在在将其应用于表的所有列时遇到问题。出于某种原因,我收到一个类型错误:'TypeError: firstCell is undefined'。我所做的只是将 firstCell = row.cells[0] 更改为 firstCell = row.cells[i] 并将代码包装在一个 for 循环中,用于表的每个列。你知道发生了什么吗?
  • 我还发现,在 row.cells[x] 中使用不同的索引简单地重复该函数两次(作为测试)也不起作用。没有错误,但似乎只有第一个功能有任何效果。我真的很困惑!
猜你喜欢
  • 1970-01-01
  • 2020-08-21
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-02-28
  • 1970-01-01
相关资源
最近更新 更多