2016-06-27 47 views
0

在下面的代碼:Backbone.js的:undelegateEvents不刪除事件

HTML

<div id="myView"> 
    <button id="test_button"> 
    Test Button 
    </button> 
    <ul id="output"></ul> 
</div> 

的JavaScript

var myView = Backbone.View.extend({ 

    initialize: function() { 
     // why doesn't this remove the previously delegated events? 
     this.undelegateEvents(); 

     this.delegateEvents({ 
      'click #test_button': 'buttonClicked' 
     }); 
    }, 

    // this event fires twice for one button click  
    buttonClicked: function() { 
     $("#output").append('<li>Button was clicked</li>'); 
    } 
}); 

$(document).ready(function(){ 
    new myView({el: "#myView"});  

    // instantiate view again 
    new myView({el: "#myView"}); 
}); 

爲什麼

this.undelegateEvents(); 

Backbone View的initialize()方法不會從以前的View的實例化中刪除先前委派的事件?上面的代碼

的jsfiddle例如:https://jsfiddle.net/billb123/o43zruea/28/

+0

我不明白你正在嘗試通過初始化視圖做兩次。如果你想在行動中看到undelegateEvents,裏面buttonClicked追加後,將它和實例化視圖一次 - 點擊僅會被解僱,那麼事件綁定被刪除。 – bdc

+0

@bdc - 我有一個Backbone應用程序,我正在開發它通過在Backbone路線中實例化它們來切換視圖,但是這會導致在任何特定視圖中委派的事件多次觸發,具體取決於該視圖的路由實例化視圖的次數(即,由用戶在視圖之間來回導航而不重新加載頁面)。我想我可以解決這個問題,只需在重新授權視圖之前刪除視圖的任何委託事件。另外,我想知道爲什麼我的例子做它的作用 - 我會認爲undelegateEvents會做到這一點。 – Bill

+2

在切換路由之前調用undelegateEvents,而不是initialize()應該爲你工作。它在initialize內部不起作用的原因是因爲您正在實例化視圖的兩個單獨實例。第二種情況不受一審事件的約束。骨幹來源:this。$ el.off('。delegateEvents'+ this.cid)。即使DOM元素相同,this.cid對於您實例化的每個視圖都是唯一的。 – bdc

回答

3

我會盡量不喊,但是請別再試圖綁定意見現有元素。讓視圖創建並擁有自己的el,然後在更換之前先致電view.remove()將其關閉。這個簡單的改變解決了觀看事件中的許多問題,如果你不這樣做,你應該總是三思而後行(再多兩次)。

在你的情況,你就必須HTML這樣的:

<script id="t" type="text/x-underscore"> 
    <div id="myView"> 
    <button id="test_button"> 
     Test Button 
    </button> 
    </div> 
</script> 
<div id="container"> 
</div> 
<ul id="output"> <!-- This is outside the container because we're going to empty and refill it --> 
</ul> 

而JavaScript是這樣的:

var myView = Backbone.View.extend({ 
    events: { 
    'click #test_button': 'buttonClicked' 
    }, 
    render: function() { 
    this.$el.html($('#t').html()); 
    return this; 
    }, 
    buttonClicked: function() { 
    $("#output").append('<li>Button was clicked</li>'); 
    } 
}); 

$(document).ready(function(){ 
    var v = new myView(); 
    $('#container').append(v.render().el); 

    v.remove(); // <----------------- Clean things up before adding a new one 

    v = new myView(); 
    $('#container').append(v.render().el); 
}); 

問題的興趣:

  1. 創建然後渲染它然後把它放在頁面上。
  2. 當你完成它時,請在視圖上調用remove
  3. 視圖進入容器內部。來電者擁有容器,該視圖擁有其el
  4. 有任何地方沒有delegateEventsundelegateEvents調用。那些存在的問題幾乎總是指向您的應用程序IMO中的結構問題。
  5. 每個視圖都是自包含的:外部世界不會與視圖內的任何東西一起玩,並且視圖會將自己的手保持在自己的手中。

更新小提琴:https://jsfiddle.net/bp8fqdgm/


但是,爲什麼不是你嘗試undelegateEvents做什麼? undelegateEvents looks like this

undelegateEvents: function() { 
    if (this.$el) this.$el.off('.delegateEvents' + this.cid); 
    return this; 
}, 

cid是按次例如唯一的,這樣每個視圖實例都使用自己獨特的命名空間爲delegateEvents結合事件。這意味着,這樣的:

this.undelegateEvents(); 
this.delegateEvents(); 

是說:

  1. 刪除該視圖的此實例已綁定的事件。這些活動將在該'.delegateEvents' + this.cid命名空間,其中cid是每個視圖實例是唯一被發現。
  2. 綁定事件視圖定義(或在delegateEvents呼叫的事件)的此實例。這些事件將使用'.delegateEvents' + this.cid命名空間進行附加。

所以你undelegateEvents呼叫被刪除事件,但不是所有的人,只有特定的事件綁定被刪除該視圖實例補充道。

this.undelegateEvents()調用實際上並沒有完成任何事情,因爲它是在錯誤的地點和錯誤的時間調用。如果new View來電者做了undelegateEvents電話:

var v = new myView({el: "#myView"});  
v.undelegateEvents(); 
new myView({el: "#myView"}); 

然後它會發生在正確的地方,並在合適的時間。當然這意味着你的路由器需要跟蹤當前的視圖,以便它能在合適的時間currentView.undelegateEvents();但如果你這樣做,那麼你會更好(IMO)採取我在答案頂部概述的方法。

+0

@TJ但它確實是一個簡單的技巧,解決了幾乎所有查看事件的問題:) –