getElementsByClassName vs querySelctorAll第二次迭代不起作用

时间:2016-09-30 15:51:29

标签: javascript dom

我想知道为什么当我使用document.getElementsByClassName时它会跳过第二次迭代?

var sameClass = document.querySelectorAll("p.kokos");

for ( var i = 0; i < sameClass.length; i++){
  sameClass[i].className = "cool";
}

var newClass = document.getElementsByClassName("new");

for ( var i = 0 ; i<= newClass.length; i++){
  newClass[i].className = "red";
}
.lw { font-size: 60px; }


.cool {
  color: #00FFFF;
}
.red {
  color: red;
}
<p class="kokos" id = "test">Hello Weaver!</p>
 <p class="kokos" id = "test">Hello Weaver!</p>
 <p class="kokos" id = "test">Hello Weaver!</p>
 <p class="new" id = "test">Hello Weaver!</p>
 <p class="new" id = "test">Hello Weaver!</p>
 <p class="new" id = "test">Hello Weaver!</p>
  

2 个答案:

答案 0 :(得分:4)

document.getElementsByClassName()会返回 直播 HTMLCollection。这意味着当您修改集合中的对象以使它们不再与类名匹配时,实际的HTMLCollection对象会从您下面被修改,从而影响您的迭代。

一种流行的解决方法是从后到前以相反的顺序迭代集合。这样,如果从集合中删除当前元素,则迭代的其余部分不会受到影响。

var newClass = document.getElementsByClassName("new");

for (var i = newClass.length - 1; i >= 0; i--){
    newClass[i].className = "red";
}

另一种解决方法是将HTMLCollection的副本复制到普通数组中,然后迭代该数组。

document.querySelectorAll()会返回固定的集合,而不是实时集合,因此它没有此问题。

答案 1 :(得分:1)

这是因为newClass不是您可能想到的静态节点数组。这是一个真人HTMLCollection。这意味着如果您更改使其中一个元素成为该集合的一部分的基础属性,它将不再是该集合的一部分。可以这样想:

你是一群戴着帽子的人。你看到有三个人戴着蓝色帽子,你称之为&#34; Blue Hats&#34;。然后你去找第一个人并给他一顶红帽子并告诉他戴上它。现在,如果你看同样的人群,你可能会期待有三个&#34; Blue Hats&#34;,但现在只有两个。换帽的人还在那里,他不是一个&#34; Blue Hat&#34;现在和你的#34; Blue Hats&#34;更小。

您的列表发生了什么。在第一个循环之后,您不再拥有第一个元素。 i已增加,因此它会转到列表中的第二个元素,但列表已更改(通过丢失第一个元素),因此您确实会转到第三个元素。使用这个类比,你现在要求第二个戴蓝帽子的人,这实际上是原来三个人中的第三个人。他也是当前戴着蓝色帽子的人中的第二人。

在下面的示例中,您可以看到元素的数量已经减少,因为您更改了使列表中的第一个元素成为列表的一部分的内容:

&#13;
&#13;
var sameClass = document.querySelectorAll("p.kokos");

for ( var i = 0; i < sameClass.length; i++){
  sameClass[i].className = "cool";
}

var newClass = document.getElementsByClassName("new");

newClass[0].className = "red";

console.log(newClass.length)
&#13;
.lw { font-size: 60px; }


.cool {
  color: #00FFFF;
}
.red {
  color: red;
}
&#13;
<p class="kokos" id = "test">Hello Weaver!</p>
 <p class="kokos" id = "test">Hello Weaver!</p>
 <p class="kokos" id = "test">Hello Weaver!</p>
 <p class="new" id = "test">Hello Weaver!</p>
 <p class="new" id = "test">Hello Weaver!</p>
 <p class="new" id = "test">Hello Weaver!</p>
&#13;
&#13;
&#13;

在最后的片段中,我使用了一个技巧来强制你的HTMLCollection成为一个数组,而不是一个实时列表。结果是您的列表没有变化,所有三个元素都被迭代:

&#13;
&#13;
var sameClass = document.querySelectorAll("p.kokos");

for ( var i = 0; i < sameClass.length; i++){
  sameClass[i].className = "cool";
}

var newClass = [].slice.call(document.getElementsByClassName("new"));

for ( var i = 0 ; i< newClass.length; i++){
  newClass[i].className = "red";
}
&#13;
.lw { font-size: 60px; }


.cool {
  color: #00FFFF;
}
.red {
  color: red;
}
&#13;
<p class="kokos" id = "test">Hello Weaver!</p>
 <p class="kokos" id = "test">Hello Weaver!</p>
 <p class="kokos" id = "test">Hello Weaver!</p>
 <p class="new" id = "test">Hello Weaver!</p>
 <p class="new" id = "test">Hello Weaver!</p>
 <p class="new" id = "test">Hello Weaver!</p>
&#13;
&#13;
&#13;