childNode 意外行为

childNode unexpected behaviour

场景

我想获取 div 的所有 child 节点并更改其颜色。 代码:

function myFunction() {
  var divv = document.getElementById("divv");
  var myCollection = divv.childNodes;
  var len = myCollection.length;
  var i;
  for (i = 0; i < len; i++) {
    myCollection[i].style.color = "red";
  }
}
<div id="divv">

  <h2>JavaScript HTML DOM</h2>

  <p>Hello World!</p>
  <p>Hello Norway!</p>
  <p>Click the button to change the color of all p elements.</p>

  <button onclick="myFunction()">Try it</button>
</div>

错误: 这是行不通的。似乎在我的 collection 中我拥有所有节点。 h2 p 文本按钮。我只期望 p h2 和按钮。

编辑 说明 注意:元素内部的空白被认为是文本,文本被认为是节点。评论也被视为节点。

所以我们需要检查节点是否为元素节点,或者使用querySelectorAll。 以下答案中的示例。感谢您的帮助。

您可以使用 children 属性 访问给定节点的子节点:

The ParentNode property children is a read-only property that returns a live HTMLCollection which contains all of the child elements of the node upon which it was called.

- MDN web docs

function myFunction() {
  var divv = document.getElementById("divv");
  var myCollection = divv.children;
  var len = myCollection.length;
  var i;
  for (i = 0; i < len; i++) {
    myCollection[i].style.color = "red";
  }
}
<div id="divv">
  <h2>JavaScript HTML DOM</h2>
  <p>Hello World!</p>
  <p>Hello Norway!</p>
  <p>Click the button to change the color of all p elements.</p>
  <button onclick="myFunction()">Try it</button>
</div>


另一种使用 ES6 的方法是将子节点散布到一个数组中并使用 .forEach:

循环遍历它们

const myFunction = () => {
  
  [...document.querySelector('#divv').children].forEach(child => {
  
    child.style.color = 'red';
  
  });
  
}
<div id="divv">
  <div class="child">
    I am a child
  </div>
  <div>
    <div class="grandchild">
      I am a grand child
    </div>
  </div>
  
  <button onclick="myFunction()">Try it</button>
</div>

或者,您可以直接使用 .forEach from the NodeList class,但之前的方法让您可以更自由地使用 Array 的方法,例如 .reduce.map 等...

const myFunction = () => {
  
  document.querySelectorAll('#divv > *').forEach(child => {
  
    child.style.color = 'red';
  
  });
  
}
<div id="divv">
  <div class="child">
    I am a child
  </div>
  <div>
    <div class="grandchild">
      I am a grand child
    </div>
  </div>
  
  <button onclick="myFunction()">Try it</button>
</div>

文本节点没有 style 属性。如果要使用childNodes,首先检查nodeType是否为1(一个Element节点):

function myFunction() {
  var divv = document.getElementById("divv");
  var myCollection = divv.childNodes;
  var len = myCollection.length;
  var i;
  for (i = 0; i < len; i++) {
    if (myCollection[i].nodeType === 1) myCollection[i].style.color = "red";
  }
}
<div id="divv">
  <h2>JavaScript HTML DOM</h2>
  <p>Hello World!</p>
  <p>Hello Norway!</p>
  <p>Click the button to change the color of all p elements.</p>
  <button onclick="myFunction()">Try it</button>
</div>

但我更喜欢在这里使用 querySelectorAllforEach:

function myFunction() {
  document.querySelectorAll('#divv > *')
    .forEach(child => child.style.color = "red");
}
<div id="divv">
  <h2>JavaScript HTML DOM</h2>
  <p>Hello World!</p>
  <p>Hello Norway!</p>
  <p>Click the button to change the color of all p elements.</p>
  <button onclick="myFunction()">Try it</button>
</div>

(或者,您可以简单地将 #divvstyle.color 设置为红色)