Javascript:addEventListener无法在for循环中工作

时间:2013-04-08 04:58:53

标签: javascript arrays for-loop addeventlistener

情况:我从API获取JSON数组。 “div”来自我的代码中的getElementByID。

问题:addEventListener只会附加到我列表中的最后一个元素。

    for(var i = 0; i < JSONarray.response.artists.length; i++){
      var artistName = JSONarray.response.artists[i];
      div.innerHTML += "<h4 id=\"artist" + i + "\" accessKey=\"" + artistName.id + "\">Artist Name: " +  artistName.name + "</h4>";
      document.getElementById("artist" + i).addEventListener("click", moreInfo, false);
    }

WEIRD THING:如果我将addEventListener放在它自己的for循环中(使用完全相同的循环脚本),那么它非常高兴并且我的所有列表项都会获得他们的监听器。

问题:我有什么理由不能将所有内容放在一个for循环中,还是我的代码?

注意:如果它恰好是浏览器,我正在使用Chrome运行它。

谢谢你的时间!

3 个答案:

答案 0 :(得分:2)

您正在修改每次迭代循环的div的innerHTML,从而导致绑定到某个节点的所有事件处理程序都将该div作为父节点丢失,因为修改innerHTML会导致从HTML重新创建所有子节点。 / p>

考虑div.innerHTML += foo;div.innerHTML = div.innerHTML + foo;的真正简写,应该明白我的意思。

编辑:我意识到我的答案已被接受(截至2013年4月8日),但我仍然觉得我可以把措辞好一些。

node.innerHTML = bar视为“替换所有节点的子节点,并且可以从给定的字符串(bar)”中解释任何HTML。它只是作为给定字符串的一部分而发生的,您通过node.innerHTML给出节点的前子节点的HTML序列化..所以您可能失去的不仅仅是事件处理程序!

如您所见,这不是添加html的最佳方式。

作为旁注,假设您必须向节点添加一堆子项,如果事件可以冒泡(请参阅HTML DOM: Which events do not bubble?,或Wikipedia's article on DOM events上的更完整列表3}}),您可以向节点添加事件处理程序,而不是向每个子节点添加处理程序,在现代浏览器(IE9 +)中,可以将许多事件处理为他们冒泡。我最近没有直接搞乱DOM中的事件冒泡,但许多第三方库很容易支持这种事件委托。使用jQuery,查看jQuery.on,绑定声明将起作用:

 jQuery(parentnodeselector).on(eventname,childselector)

AFAIK,你自己处理事件冒泡并不是非常困难......你 需要能够通过event.targetevent.target的父母识别然而,事件通过正确的孩子冒出来了。

答案 1 :(得分:1)

不应鼓励内联事件处理程序,尤其是在使用innerHTML动态创建时。我甚至还记得在这个场景中读到IE中发生的事情。尝试使用类似的东西,它使用更合适的方法向DOM添加元素:

for (var i = 0; i < JSONarray.response.artists.length; i++) {
    var artistName = JSONarray.response.artists[i];
    var newH4 = document.createElement("h4");
    newH4.id = "artist" + i;
    newH4.accessKey = artistName.id;    // You might have to use newH4.setAttribute("accessKey", artistName.id) instead
    newH4.innerHTML = "Artist Name: " +  artistName.name;
    newH4.addEventListener("click", moreInfo, false);
    div.appendChild(newH4);
}

如果您关心,旧的IE浏览器没有addEventListener - 因此您需要检查addEventListener,并使用attachEvent(如果它不可用)。只是一个警告。类似的东西:

if (newH4.addEventListener) {
    newH4.addEventListener("click", moreInfo, false);
} else if (newH4.attachEvent) {
    newH4.attachEvent("onclick", moreInfo);
} else {
    newH4.onclick = moreInfo;
}

此外,您不应在循环中的同一元素上使用innerHTML。创建一个大字符串并在for循环中附加到该字符串更有效,然后在>循环之后的元素上设置innerHTML。随着JSONarray.response.artists数组的大小增加,这变得非常重要。

答案 2 :(得分:0)

它看起来像是一个dom更新问题

for(var i = 0; i < JSONarray.response.artists.length; i++){
      var artistName = JSONarray.response.artists[i];
      div.innerHTML += '<h4 id="artist' + i + '" accessKey="' + artistName.id + '" onclick="moreInfo(this)">Artist Name: ' +  artistName.name + '</h4>';
}

演示:Fiddle