Javascript addEventListener在循环中

时间:2012-03-30 23:41:57

标签: javascript

我正在尝试为我在循环中生成的一些元素添加一个事件监听器。我必须使用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>

该事件仅适用于最后一个按钮。我在这里缺少什么?

1 个答案:

答案 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内容连接到字符串,然后销毁旧节点并从新字符串创建新节点

这非常低效,正如您已经看到的,它会销毁与原始元素相关的所有数据,包括处理程序。