2012-03-30 24 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