JavaScript插入之前无法正常工作

时间:2015-07-28 18:25:13

标签: javascript html css

试图在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有时只是倒置,而不是总是。

初次点击按钮会在控制台上显示:

enter image description here

第二次点击:

enter image description here

经过一番点击后:

enter image description here

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

4 个答案:

答案 0 :(得分:5)

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

&#13;
&#13;
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);
}
&#13;
<div id="parent">
  <div id="first">Div 1</div>
  <div id="second">Div 2</div>
</div>
<button onclick="invertDivs('parent');">Invert Divs</button>
&#13;
&#13;
&#13;

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

答案 1 :(得分:3)

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

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

很明显,你不在乎这里的文本节点。你有很多选择。

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

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

&#13;
&#13;
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]);
}
&#13;
<div id="parent">
  <div id="first">Div 1</div>
  <div id="second">Div 2</div>
</div>
<button onclick="invertDivs('parent');">Invert Divs</button>
&#13;
&#13;
&#13;

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

答案 2 :(得分:1)

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

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

要解决此问题,请使用children属性。这将选择子元素(而不是节点)。

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>

答案 3 :(得分:1)

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