2011-08-09 52 views
7

我有一種情況,一個div的html內容更改爲其他內容,然後又改回來了。 jquery ui的一些控制行爲不當。我將問題簡化爲以下代碼片段,它基本上表明與該按鈕關聯的事件處理程序不再觸發。我假設這些垃圾是在他們走後的某個時候收集的。所以我的問題是 -html重置後javascript事件丟失

如何防止事件處理程序從DOM丟失垃圾收集?

據我所知,我可以重新分配click()函數,但由於我使用外部庫(jQuery UI),我真的不知道它是如何處理我的控件。我只想讓他們的活動像以前一樣恢復。

<div id="container"> 
    <p>This container has a button, which will forget its click()...</p> 
    <input id="testbutton" type="button" value="Click Me!"/> 
</div> 

<script type="text/javascript"> 
    $(function(){ 
     $("#testbutton").click(
      function(){ 
       alert("Button has been clicked!"); 
     }) 
    }); 
</script> 

<div> 
    <p>... when this button reseats html</p> 
    <input id="actionbutton" type="button" value="Toggle"/> 
</div> 

<script type="text/javascript"> 
    var toggle = false; 
    var html; 
    $(function(){ 
     $("#actionbutton").click(
      function(){ 
       toggle = !toggle; 
       if(toggle){ 
        html = $("#container").html(); 
        $("#container").html(""); 
       } else $("#container").html(html); 
     }) 
    }); 
</script> 

這個jfiddle顯示我有問題。

+0

另一種方法是不覆蓋容器中的html,而是使用detach方法將其刪除,然後將其添加回dom - http://jsfiddle.net/8S5E4/4/。似乎這不是你想要的(基於小提琴中的評論) –

回答

4

答案很簡單:使用.live

$(function(){ 
    $("#testbutton").live('click', 
     function(){ 
      alert("Button has been clicked!"); 
    }) 
}); 

下面是更新小提琴:http://jsfiddle.net/mrchief/8S5E4/1/

說明:當您更改DOM時,附加該元素的事件處理程序也將被刪除。使用.live將事件處理程序附加到「body」(並通過DOM元素進行過濾),以便即使在刪除/添加相同的DOM元素後仍然「存在」。

可以使用.delegate也能達到同樣的效果:

$(function(){ 
    $('#container').delegate('#testbutton', 'click', 
     function(){ 
      alert("Button has been clicked!"); 
    }) 
}); 

使用.delegate小提琴:http://jsfiddle.net/mrchief/8S5E4/6/

我會建議使用.delegate超過.live爲:

  • 可以取消事件冒泡。當您使用live時,事件會一直冒泡到body,然後您的處理程序會被調用,因此無法取消其冒泡。 (從jQuery 1.4開始,這可以通過使用上下文參數來阻止:http://api.jquery.com/live/
  • 由於您特別附加到DOM元素,因此每次單擊主體上任何其他DOM元素時都不會調用它因此,它現在更少工作,因此性能更高。

這是一篇很好的文章,精彩地解釋了differences between live, delegate and bind並討論了每種方法的細微差別。感謝@andyb指出這個鏈接。

+0

非常感謝您提供非常全面的答案!我仍然有一個問題,因爲我並不是真正讓click()事件發生的人,它是jquery ui。我會做的是發佈另一個問題,並在那裏提出那個特定的問題。 – Gleno

+0

很高興幫助!不要忘記接受答案! – Mrchief

2

jQuery的事件代表團救援

$("#container").delegate('#testbutton', 'click', 
    function(){ 
     alert("Button has been clicked!"); 
}); 

注:.delegate()is more efficient.live()

+0

只是出於興趣:效率問題是否仍然相同?您發佈的文章已超過一年,並且是在jquery 1.4時代編寫的。 jQuery團隊解決了這個問題還是應該開始使用委託來處理這些情況? – GNi33

+0

從1.4開始,live的上下文參數也是'$(「div.clickme」,$(「#container」)[0])。live(「click」,function(){ // Live handler called。 }); ':http://api.jquery.com/live/ – Mrchief

+1

@ GNi33,請參閱@ Mrchief的答案,瞭解爲什麼委託更好的更多原因,也是[更新的文章](http://www.alfajango.com/blog/the-difference-between-jquerys-bind-live-and-delegate /)之間的區別。也就是說,我同意鏈接的文章是老的,jQuery團隊可能已經收緊了'.live()'自從1.4 – andyb

2

發生這種情況,因爲你要綁定一個事件來#testbutton其中#container裏面住在文件準備就緒。當您清除#container的HTML時,您也將失去該#testbutton綁定的點擊事件。而是,click事件引用的元素不再存在。

如果您希望該按鈕事件持續發生,請嘗試使用live()綁定或delegate()來自父元素的事件。


使用live()

$(function(){ 
    $("#testbutton").live("click", function() { 
     alert("Button has been clicked!"); 
    }) 
}); 

附加一個處理程序的情況下爲當前選擇現在和將來匹配這,所有的元素。


使用delegate()

$(function(){ 
    $("#container").delegate("#testbutton", "click", function() { 
     alert("Button has been clicked!"); 
    }) 
}); 

附加一個處理程序,以一個或多個事件的選擇,現在或將來所有匹配的元素,基於一組特定的根元素。