Backbone.js:未删除事件不删除事件



在以下代码中:

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();

在骨干视图的initialize()方法中,没有从视图的先前实例化中删除先前授权的事件?

jsfiddle上述代码的示例:https://jsfiddle.net/billb123/o43zruea/28/

我会尽量不要大喊,但请停止尝试将视图绑定到现有元素。让视图创建并拥有自己的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调用。这些人的存在几乎总是指出您的应用程序中的结构性问题。
  5. 每个观点都是自我包含的:外界在视图内没有任何扮演任何东西,并且视图使自己的手保持自身。

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


但是您为什么不尝试undelegateEvents做任何事情?undelegateEvents看起来像这样:

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)以我在答案的顶部概述的方法会更好。

最新更新