为什么在我的Backbone应用程序中多次触发click事件?

时间:2012-05-03 02:07:00

标签: javascript backbone.js mouseevent backbone-events

我正在创建一个Backbone.js应用程序,它包含一个索引视图和几个基于id的子视图。所有视图都与mousedown和mouseup事件绑定在一起。但是每当我从子视图转到索引视图然后再次转到任何子视图时,当前子视图中的mousedown和mouseup事件将再次被触发,这意味着当我单击子视图时,会有几个连续的触发了mousedown事件,随后触发了几个连续的mouseup事件。

查看完代码后,我终于发现导致此问题的是路由器。我的部分代码如下:

    routes: {
        "": "index",
        "category/:id": "hashcategory"  
    },

    initialize: function(options){
        this._categories = new CategoriesCollection();
        this._index = new CategoriesView({collection: this._categories});

    },

    index: function(){
        this._categories.fetch();
    },

    hashcategory: function(id){
        this._todos = new TodosCollection();
        this._subtodolist = new TodosView({ collection: this._todos, 
                                            id: id                                              
                                         });
        this._todos.fetch();
   }

如您所见,我在路由器的initialize方法中创建了索引集合和视图,但是我在路由器的相应路由功能中创建了子视图集合和视图。我尝试将索引集合和视图放在index函数中,索引视图中的click事件的行为方式与子视图相同。所以我认为这就是为什么mousedown和mouseup会被触发几次。

但问题是,我必须使用id作为发送到子视图的参数之一。所以我无法在initialize方法中创建子视图。更重要的是,我已经看到其他人基于Backbone的项目,其中一些也在相应的路由功能中创建子集合和视图,但他们的应用程序运行完美。所以我不知道问题的根源是什么。有人能给我一些想法吗?

1 个答案:

答案 0 :(得分:1)

听起来你有代表问题,因为:

  

所有子视图都使用相同的<div>元素

骨干视图使用jQuery el <div>绑定到事件。如果您的视图使用el作为其<div>,然后您通过替换包含的HTML将相同的<div>用于其他视图,那么您最终会将两个视图附加到delegate通过两个不同的delegate来电。如果再次交换视图,您将有三个视图通过三个<div id="view-goes-here"></div> 接收事件。

例如,假设我们有这个HTML:

var V0 = Backbone.View.extend({
    events: { 'click button': 'do_things' },
    render: function() { this.$el.html('<button>V0 Button</button>'); return this },
    do_things: function() { console.log('V0 clicked') }
});        
var V1 = Backbone.View.extend({
    events: { 'click button': 'do_things' },
    render: function() { this.$el.html('<button>V1 Button</button>'); return this },
    do_things: function() { console.log(V1 clicked') }
});

和这些观点:

which

我们用这样的东西在它们之间切换(当然which = (which + 1) % 2; var v = which == 0 ? new V0({el: $('#view-goes-here') }) : new V1({el: $('#view-goes-here') }); v.render(); 从0开始):

which = (which + 1) % 2;
if(current)
    current.undelegateEvents(); // This detaches the `delegate` on #view-goes-here
current = which == 0
      ? new V0({el: $('#view-goes-here') })
      : new V1({el: $('#view-goes-here') });
current.render();

然后你将遇到我上面描述的多代理问题,这种行为似乎与你所描述的症状相符。

以下是一个易于查看的演示:delegate

解决此问题的一种快捷方法是在呈现新视图之前在当前视图上调用http://jsfiddle.net/ambiguous/AtvWJ/

el

演示:undelegateEvents

更好的方法是为每个视图提供自己独特的delegate,这样当您替换HTML时,所有内容(包括<div><div>real stuff</div></div>绑定)都会消失。你最终可能会遇到很多{{1}}结构,但这不值得担心。