2012-03-30 76 views
3

我想添加一个事件监听器给我在循环中生成的一些元素。我必须使用div.lastChild - 虽然在这个例子中它非常愚蠢。但这只是示范:循环内的Javascript addEventListener

<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> 

该事件只适用于最后一个按钮。我在这里错过了什么?

回答

3

为什么它不起作用。

当你做到这一点...

div.innerHTML += '<input type="button" value="' + i + '" />'; 

...在循环中你摧毁旧的DOM节点内div(因此他们的处理程序),并重新创建新节点的每一次迭代(但没有处理程序)。销毁包括在先前迭代中添加的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内容串联到,然后摧毁旧节点并从新字符串中创建新节点。

这是非常低效的,正如你已经看到的,它破坏了与原始元素相关的任何数据,包括处理程序。


+2

非常感谢您的先生。 – grjj3 2012-03-31 00:07:16