2

情况:我从 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);
    }

奇怪的事情:如果我将 addEventListener 放在它自己的 for 循环中(使用完全相同的循环脚本),它会非常高兴,我的所有列表项都会得到它们的监听器。

问题:我不能把所有东西都放在一个 for 循环中,还是我的代码有什么原因吗?

注意:我使用 Chrome 来运行它,如果它碰巧是浏览器的话。

谢谢你的时间!

4

3 回答 3

2

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

考虑一下这div.innerHTML += foo;真的是简写,div.innerHTML = div.innerHTML + foo;我的意思应该很明显。

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

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

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

作为旁注,假设您确实必须向节点添加一堆子节点,如果事件可以冒泡(请参阅HTML DOM:哪些事件不会冒泡?或维基百科关于 DOM 事件的文章的更完整列表),而不是除了为每个子节点添加处理程序之外,您还可以向节点添加事件处理程序,并且在现代浏览器 (IE9+) 中,许多事件可以在冒泡时进行处理。最近我还没有直接处理 DOM 中的事件冒泡,但是许多第三方库很容易支持这种事件委托。使用 jQuery,查看jQuery.on和绑定声明会像这样工作:

 jQuery(parentnodeselector).on(eventname,childselector)

AFAIK,自己处理事件冒泡并不难......但是,如果事件通过正确的孩子冒泡,您需要能够识别 viaevent.target和的父母。event.target

于 2013-04-08T05:16:57.837 回答
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- 因此您需要检查addEventListenerattachEvent如果它不可用则使用。只是一个警告。就像是:

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

于 2013-04-08T05:26:57.347 回答
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>';
}

演示:小提琴

于 2013-04-08T05:13:50.103 回答