情况:我从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运行它。
谢谢你的时间!
答案 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.target
和event.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