Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/backbone.js/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Templates Click在主干中调用函数两次_Templates_Backbone.js_View_Duplicates - Fatal编程技术网

Templates Click在主干中调用函数两次

Templates Click在主干中调用函数两次,templates,backbone.js,view,duplicates,Templates,Backbone.js,View,Duplicates,我已经在主干视图上创建了两次警报触发的快速示例 这并没有什么特别的,我真正理解的是如何正确调用单独的视图,这样它们就不会触发以前的click方法。现在我生成了两个视图,第二个视图覆盖了#boxSearch中的表单。当我单击按钮搜索时,它还会生成警报doSearch SearchLocation。我只希望看到alertDoSearchLatitude。我做错了什么 var Geo = { Views: {}, Templates: {} }; Geo.Templates.Sea

我已经在主干视图上创建了两次警报触发的快速示例

这并没有什么特别的,我真正理解的是如何正确调用单独的视图,这样它们就不会触发以前的click方法。现在我生成了两个视图,第二个视图覆盖了#boxSearch中的表单。当我单击按钮搜索时,它还会生成警报
doSearch SearchLocation
。我只希望看到alert
DoSearchLatitude
。我做错了什么

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"