【问题标题】:Javascript: addEventListener not working in a for-loopJavascript:addEventListener 不在 for 循环中工作
【发布时间】:2013-04-08 04:58:52
【问题描述】:

情况:我从 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 来运行它,如果它碰巧是浏览器的话。

感谢您的宝贵时间!

【问题讨论】:

  • 你确定没有匿名函数内联你引用moreInfo吗?
  • 如果您不需要对点击事件进行任何特殊处理,只需使用 document.getElementById(...).onclick=moreInfo;或者只是内联 <... onclick="moreInfo('+i+')">
  • 您的moreInfo 是如何定义的?
  • 哦,刚刚学习了innerHTML的多重替换。从来没有在 innerHTML 上使用过事件处理程序,所以从来没有遇到过这个问题。自从发现 jQuery 后,我永远不会使用自己的 Jason 处理。您是否考虑过 jQuery 可以极大地简化您的操作

标签: javascript arrays for-loop addeventlistener


【解决方案1】:

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

考虑到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 上的更完整列表) ,而不是为每个子节点添加一个处理程序,您还可以向 parent 节点添加一个事件处理程序,并且在现代浏览器 (IE9+) 中,许多事件可以按 冒泡。最近我还没有直接处理 DOM 中的事件冒泡,但是许多第三方库很容易支持这种事件委托。使用 jQuery,查看jQuery.on,绑定声明的工作方式类似于:

 jQuery(parentnodeselector).on(eventname,childselector)

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

【讨论】:

  • 现在这是我从未听说过的有趣信息。我不知道使用 innerHTML 会抛弃事件处理程序。他们不知道/不知道的小事。
  • @AsdAsd 如果你不使用innerHTML,这种事情就不会发生:)
  • @AsdAsd:是的......即使我知道你接受了我的回答,我还是添加了一些信息,只是为了澄清,以及另一个你可能不知道的事件绑定选项。
【解决方案2】:

不应鼓励内联事件处理程序,尤其是在使用 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 循环内,然后在循环 after 元素上设置 innerHTML 会更有效。随着 JSONarray.response.artists 数组大小的增加,这一点变得更加重要。

【讨论】:

  • 我很想知道为什么原始代码无法正常工作。我只是累了它,它成功地创建了 DOM 元素,具有正确的 ID 和循环内的 document.getElementByID 成功找到它们,但只有最后一个附加了处理程序。
  • @akonsu 没错,我想我的意思是,如果你以“正确”的方式做事,你就不应该遇到这样的问题。无论哪种方式,有趣的是为什么它很奇怪。你有小提琴要测试吗?
  • 这是我从@ArunPJohny 的一个创建的:plnkr.co/edit/5Al4eo4ohQaoFS8IpdqE
  • @akonsu 如果您查看 JayC 的答案,那应该可以解释 为什么 :)
【解决方案3】:

貌似是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

【讨论】:

  • 轻微的语法问题;转义 moreInfo() 周围的引号
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2011-06-02
  • 2013-12-25
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-02-03
  • 1970-01-01
相关资源
最近更新 更多