在以下代码中:
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);
});
兴趣点:
- 创建视图,然后将其放在页面上。
- 完成后在视图上呼叫
remove
。 - 视图进入容器内部。呼叫者拥有容器,视图拥有其
el
。 - 任何地方都没有
delegateEvents
或undelegateEvents
调用。这些人的存在几乎总是指出您的应用程序中的结构性问题。 - 每个观点都是自我包含的:外界在视图内没有任何扮演任何东西,并且视图使自己的手保持自身。
更新的小提琴: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();
说:
- 删除视图实例绑定的事件。这些事件将在
'.delegateEvents' + this.cid
名称空间中找到,其中cid
对于每个视图实例都是唯一的。 - 绑定视图的此实例定义的事件(或
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)以我在答案的顶部概述的方法会更好。