【问题标题】:JavaScript insertBefore not working properlyJavaScript insertBefore 无法正常工作
【发布时间】:2023-03-27 09:35:01
【问题描述】:

为了让我对this问题的回答更加灵活:

function invertDivs(parentDiv) {
  var first = document.getElementById(parentDiv).firstChild;
  console.log(first);
  var second = document.getElementById(parentDiv).lastChild;
  console.log(second);
  document.getElementById(parentDiv).insertBefore(second, first);
}
<div id="parent">
  <div id="first">Div 1</div>
  <div id="second">Div 2</div>
</div>
<button onclick="invertDivs('parent');">Invert Divs</button>

但是,div 只是有时会反转,并非总是如此。

第一次点击按钮会在控制台上产生这个:

第二次点击:

点击几下后:

我对代码有什么问题感到困惑。我选择父 div 的第一个孩子,并为最后一个孩子做同样的事情。然后我只是在第一个 div 之前插入当前的第二个 div。这就是函数的结束。根据insertBefore 函数的要求,它们也是父 div 的直接子级。

【问题讨论】:

  • 请记住,文本节点也是子节点。我猜你想改用firstElementChild,或者childNodes[0]
  • HTML 中的每个空格都将被视为text node。当您摆脱 HTML 中的所有空格时,您可能不会遇到问题。但这是一种痛苦。相反,您需要检查 nodeValue1 是元素节点,3 是文本节点。因此,您需要添加额外的检查以避免处理1's

标签: javascript html css


【解决方案1】:

如 cmets 中所述,firstChildlastChild 可以为元素之间的空白返回文本节点。您可以使用firstElementChildlastElementChild 忽略这些。

function invertDivs(parentDiv) {
  var first = document.getElementById(parentDiv).firstElementChild;
  console.log(first);
  var second = document.getElementById(parentDiv).lastElementChild;
  console.log(second);
  document.getElementById(parentDiv).insertBefore(second, first);
}
<div id="parent">
  <div id="first">Div 1</div>
  <div id="second">Div 2</div>
</div>
<button onclick="invertDivs('parent');">Invert Divs</button>

有关旧版浏览器可能需要的其他一些解决方法,请参阅element.firstChild is returning '<TextNode ...' instead of an Object in FF

【讨论】:

  • 甚至不知道添加了这些元素变体 - 看来我需要复习一下 DOM。
  • @Barmar 本质上是firstElementChild parent.children[0]
  • @Abdul 看起来是这样。
  • @Abdul 不,parent.children[0]parent.childNodes[0] 的行为都像 parent.firstChild。似乎唯一能准确找到唯一子元素的方法确实是firstElementChildlastElementChild。所有其他人都找到了各种元素,包括空格和换行符。看看W3C's reference
【解决方案2】:

您没有考虑文本节点。在上面的 HTML 示例中,有 5 个节点。

[0] => TextNode
[1] => #first
[2] => TextNode
[3] => #second
[4] => TextNode

很明显,您并不关心这里的文本节点。你有很多选择。

一种选择是过滤掉所有的文本节点。 (不能使用Array.prototype.filter方法,因为childNodes不是数组,而是NodeList)

这将为您提供一个仅包含 DOM 元素的数组。

function invertDivs(parentNodeId) {
  var childElements = [],
      parentNode = document.getElementById(parentNodeId);
  
  //Filter out the child nodes that aren't elements.
  //parentNode.childNodes is a NodeList, and not an array (even though it looks like one)
  for (var i = 0; i < parentNode.childNodes.length; ++i) {
    if (parentNode.childNodes[i].nodeType === 1)
      childElements.push(parentNode.childNodes[i]);
  }
  
  parentNode.insertBefore(childElements[childElements.length - 1], childElements[0]);
}
<div id="parent">
  <div id="first">Div 1</div>
  <div id="second">Div 2</div>
</div>
<button onclick="invertDivs('parent');">Invert Divs</button>

另一种选择是使用更现代的 DOM API 属性:请参阅 Barmar 或 GolezTrol 的答案。如果您的观众支持 IE9+ 浏览器,它们的性能会更好。

【讨论】:

    【解决方案3】:

    这不是随机的。如果我单击 2 次,将 Div 2 添加到列表末尾,然后单击 3 次以在列表末尾获取 Div 1。这种模式重复。

    原因是因为中间还有下一个节点。这是元素之间的空白。

    要解决此问题,请使用children 属性。这会选择子 elements(而不是 nodes)。

    function invertDivs(parentDiv) {
      var parent = document.getElementById(parentDiv);
      var first = parent.children[0];
      console.log(first);
      var second = parent.children[parent.children.length-1];
      console.log(second);
      document.getElementById(parentDiv).insertBefore(second, first);
    }
    <div id="parent">
      <div id="first">Div 1</div>
      <div id="second">Div 2</div>
    </div>
    <button onclick="invertDivs('parent');">Invert Divs</button>

    【讨论】:

    • firstElementChild 本质上是parent.children[0]
    • 是的,虽然它没有失败但在没有孩子时返回null。所以实际上firstElementChild 更容易使用。请注意浏览器兼容性。 firstElementChild 在 IE9+ 中可用。 children 已经在早期版本中可用,尽管它在 IE8 和之前的版本中有一个小错误:它还包括 cmets...如果您不关心 IE8-(而且您不应该),那么 firstElementChild 是最简单的选择。
    【解决方案4】:

    Node.firstChild 的 MDN 文档 (https://developer.mozilla.org/en-US/docs/Web/API/Node/firstChild) 中给出了您问题的答案。如果您参考文档,您将理解为什么将 #text 作为第一个节点。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2013-10-10
      • 2015-05-23
      • 2012-11-02
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多