我正在尝试为我在循环中生成的一些元素添加一个事件监听器。我必须使用div.lastChild
- 尽管在这个例子中它非常愚蠢。但那只是示范:
<div id="someArea">
</div>
<script type="text/javascript">
var func = function() {
alert('Callback works');
}
var func1 = function() {
alert('Test');
}
var func2 = function() {
alert('Test2');
}
var div = document.getElementById("someArea");
var callbacks = [func, func1, func2];
for(var i = 0; i <= 2; i++) {
div.innerHTML += '<input type="button" value="' + i + '" />';
(function(i) {
console.log(div.lastChild);
div.lastChild.addEventListener('click', callbacks[i], false);
}(i));
}
</script>
该事件仅适用于最后一个按钮。我在这里缺少什么?
答案 0 :(得分:3)
为什么它无效。
当你这样做时......
div.innerHTML += '<input type="button" value="' + i + '" />';
...在循环的每次迭代中,你正在销毁div
内的旧DOM节点(以及它们的处理程序),并重新创建新节点(但没有处理程序)。销毁包括先前迭代中添加的input
元素。
这就是为什么只有最后一个有效的原因,因为在那一点之后,你已经将处理程序分配给最后一个元素,但其他元素是全新的而且未受影响。
解决方案。
不要将DOM视为HTML标记字符串,而是考虑使用DOM方法创建元素...
for(var i = 0; i <= 2; i++) {
var input = document.createElement('input');
input.type = 'button';
input.value = i;
input.addEventListener('click', callbacks[i], false);
div.appendChild(input);
}
请注意,我删除了立即调用的函数。对于您的代码,由于i
在循环中而不是稍后在处理程序中进行评估,因此没有必要。
DOM不是HTML,但.innerHTML
让您认为它是。
了解innerHTML
非常重要。使用DOM时,没有HTML标记。因此,当您获取 .innerHTML
时,正在分析DOM,并创建一个新的HTML字符串。
当将分配给.innerHTML
时,您将销毁所有当前内容,并将其替换为从HTML字符串创建的新节点。
所以,当你这样做......
div.innerHTML += '<input...>'
...您首先从当前内容创建新的HTML字符串,然后将新的HTML内容连接到字符串,然后销毁旧节点并从新字符串创建新节点
这非常低效,正如您已经看到的,它会销毁与原始元素相关的所有数据,包括处理程序。