Templates Click在主干中调用函数两次
我已经在主干视图上创建了两次警报触发的快速示例 这并没有什么特别的,我真正理解的是如何正确调用单独的视图,这样它们就不会触发以前的click方法。现在我生成了两个视图,第二个视图覆盖了#boxSearch中的表单。当我单击按钮搜索时,它还会生成警报Templates Click在主干中调用函数两次,templates,backbone.js,view,duplicates,Templates,Backbone.js,View,Duplicates,我已经在主干视图上创建了两次警报触发的快速示例 这并没有什么特别的,我真正理解的是如何正确调用单独的视图,这样它们就不会触发以前的click方法。现在我生成了两个视图,第二个视图覆盖了#boxSearch中的表单。当我单击按钮搜索时,它还会生成警报doSearch SearchLocation。我只希望看到alertDoSearchLatitude。我做错了什么 var Geo = { Views: {}, Templates: {} }; Geo.Templates.Sea
doSearch SearchLocation
。我只希望看到alertDoSearchLatitude
。我做错了什么
var Geo = {
Views: {},
Templates: {}
};
Geo.Templates.SearchLocation = _.template( $("#tpl-search-location").html());
Geo.Templates.SearchLatitude = _.template( $("#tpl-search-latitude").html());
Geo.Views.SearchLocation = Backbone.View.extend({
initialize: function() {
this.render();
},
el: $("#boxSearch"),
template: Geo.Templates.SearchLocation,
render: function()
{
$(this.el).html(this.template);
},
events: {
"click input[type=button]": "doSearch"
},
doSearch: function(e) {
e.preventDefault();
alert('doSearch SearchLocation');
}
});
Geo.Views.SearchLatitude = Backbone.View.extend({
initialize: function() {
this.render();
},
el: $("#boxSearch"),
template: Geo.Templates.SearchLatitude,
render: function()
{
$(this.el).html(this.template);
},
events: {
"click input[type=button]": "doSearch"
},
doSearch: function(e) {
e.preventDefault();
alert('doSearch SearchLatitude');
}
});
$(document).ready(function(e) {
var searchLocation = new Geo.Views.SearchLocation();
var searchLatitude = new Geo.Views.SearchLatitude();
});
向元素添加其他视图时,它不会自动删除旧视图;如果要这样做,必须显式调用
yourFirstView.remove()
。然而,这样做也会移除元素;如果只想在不删除元素的情况下解除事件绑定,可以改用yourFirstView.undelegateEvents()
值得一提的是,这是主干网的一种故意行为:当主干网使用jQuery(或Zepto…以两者为准,让我们假设jQuery并根据需要替换)将事件绑定到视图中的元素时,在单个el
上拥有2+个视图通常是有帮助的,它处理事件就像事件从元素冒泡到el
元素一样
您可以从注释源中的delegateEvents
中找到此行为的来源:
关键是理解与this.$el.on(eventName,method)相关的“可委托”事件代码>和此.el.on(事件名称、选择器、方法)代码>
有关jQuery,请参阅“直接和委派事件”一节
关于你的代码,希望你能明白为什么它是这样运行的。您没有覆盖el
元素本身,因此两个委派的绑定仍然有效。这是主干应用程序经常遇到的“重影视图”问题:
- 将视图附加到DOM元素
- 将另一个视图附加到同一DOM元素
- 在DOM元素上触发事件(或者更糟的是,在其他地方触发两个视图都侦听的事件)
- 这两个视图都会启动它们的事件处理程序,通常会造成严重破坏
正如@machineghost所指出的,您的代码中没有任何内容可以解除第一个视图的绑定,因此这两个视图都附加到#boxSearch
,并且这两个视图都将响应单击事件。有几种方法可以解决这个问题:
- 您可以在事件处理程序中调用
e.stopPropagation()
()(我认为这就是您试图用e.preventDefault()执行的操作)。这将防止事件触发后冒泡,因此最后定义的视图将捕获它。这是可行的,但请注意,这两个视图仍然存在,过时的重影视图可能还有其他副作用
- 您可以让每个视图使用类
.boxSearch
呈现自己的DOM元素,然后对不再需要的DOM元素调用view.remove()
。这可能是最干净的选择,但这意味着要动态创建大部分DOM,这比用HTML编码要贵一些,也更难管理
- 您可以为每个视图提供一个清理方法,例如
.clear()
或.exit()
,这些方法可以调用视图.undelegateEvents()
和视图.stopListening()
。然后确保在处理完视图后调用此方法
如果您非常小心地确保调用它并确保它清除所有需要清除的内容,那么它工作正常。有时您希望确保视图层次结构不会导致重叠侦听器绑定。例如,如果您有带UL-s和子UL-s的树状视图。这些UL存在于DOM中,您希望将主干视图绑定到a;;利斯。
然后,您应该在“>”的帮助下使用更严格的选择器,即,而不是:
"click li .btn": "handleClick"
你应该:
"click li > .btn": "handleClick"
注意:不要在此处使用view.remove()
——这将从DOM中删除#boxSearch
元素,而不仅仅是解除视图绑定。这是一个很好的答案。它有非常好的细节,并解释了为什么它是一个问题以及如何解决它。非常感谢你。
"click li > .btn": "handleClick"