对于大多数有经验的用户来说,这听起来可能是愚蠢的,甚至是微不足道的,但是我只是几个小时前才登陆前端javascript,我必须说我对insertBefore javascript函数的行为感到有点困惑。

我的意图是简单而简单的:我有一个包含行和单元格的表,并且在每一行中都有一个带有按钮的单元格,其唯一目的是复制该单元格(及其所有内容)并将新复制的单元格放在右边原来的旁边。

我有一个像这样的javascript函数:

// id -> the id of the table I want the row to be added
// caller -> the object of the element that called the function
function duplicateRow(id, caller)
{
    const table = document.getElementById(id);
    const row   = caller.parentNode.parentNode;  // Caller is always a button inside a cell inside a row
    const clone = row.cloneNode(true);

    table.insertBefore(clone, row.nextElementSibling);
}


此函数的调用方式如下(摘自我的HTML):

<tr>
    <td>
        <input type="text" name="competence-name">
    </td>
    <td>
        <button name="duplicate-row-button" onclick="duplicateRow( 'competencies-table', this )"></button>
    </td>
</tr>


因此,我希望得到的是,每次单击“重复行”按钮时,它将创建单击该按钮的行的精确副本,并将其添加到该行之后。

我的问题不在于复制(正如人们所期望的那样正确而顺利地完成),而在于放置新行的位置:


第一次,当只有一行时,将其放置在末尾(因为nextSiblingnull)。
第二次单击第一行上的按钮(尽管现在紧随其后),新行再次放置在表的末尾(好像第一行的nextSibling仍然是null)。
依此类推(将重复项与新添加的行混合时,甚至会发生更奇怪的放置)。


将新节点添加到DOM时,是否不应该更新nextSibling和/或rowIndex属性?有强迫他们更新的方法吗?我有什么错?我的代码,我对它应该如何工作的理解?

我肯定会接受任何可能的解释/解决方案/替代方案来实现我所需要的,并在此先感谢大家!

最佳答案

问题是初始表行包装在tbody元素中(您可以省略它的开始和结束标签),根据表的内容模型,这是必需的。但是,当您以编程方式添加更多行时,它们被插入到tbody之外,并且您的初始行是该隐式tbody的唯一子级,因此DOM树如下所示:

<table>
  <tbody>
    <tr></tr>
  </tbody>
  <tr></tr>
  <tr></tr>
</table>


为了解决这个问题,我建议向克隆行的父项添加一个克隆:



function duplicateRow(caller){
  const row   = caller.parentNode.parentNode;  // Caller is always a button inside a cell inside a row
  const clone = row.cloneNode(true);

  row.parentNode.insertBefore(clone, row.nextElementSibling);
}

<table id="competencies-table">
  <tr>
    <td>
      <input type="text" name="competence-name">
    </td>
    <td>
      <button name="duplicate-row-button" onclick="duplicateRow( this )">Duplicate</button>
    </td>
  </tr>
</table>

09-27 22:22
查看更多