2013-07-23 153 views
3

我们有一个单独的骨干视图,由一个侧栏和几个子视图组成。为了简单起见,我们决定使用单个render函数管理侧边栏和子视图。然而,click .edit事件似乎在点击其中一个侧边栏项目后会多次触发。例如,如果我从“常规”开始并单击.edit,则hello会触发一次。如果我再点击边栏上的.profile,然后再次点击.edithello会发生两次。有任何想法吗?重新渲染子视图后,骨干事件触发多次

查看

events: { 
    "click .general": "general", 
    "click .profile": "profile", 
    "click .edit": "hello", 
}, 

general: function() { 
    app.router.navigate("/account/general", {trigger: true}); 
}, 

profile: function() { 
    app.router.navigate("/account/profile", {trigger: true}); 
}, 

render: function(section) { 
    $(this.el).html(getHTML("#account-template", {})); 
    this.$("#sidebar").html(getHTML("#account-sidebar-template", {})); 
    this.$("#sidebar div").removeClass("active"); 
    switch (this.options.section) { 
    case "profile": 
     this.$("#sidebar .profile").addClass("active"); 
     this.$("#content").html(getHTML("#account-profile-template")); 
     break; 
    default: 
     this.$("#sidebar .general").addClass("active"); 
     this.$("#content").html(getHTML("#account-general-template")); 
    } 
}, 

hello: function() { 
    console.log("Hello world."); 
}, 

路由器

account: function(section) { 
    if (section) { 
    var section = section.toLowerCase(); 
    } 
    app.view = new AccountView({model: app.user, section: section}); 
}, 

解决方案

我的解决办法是改变路由器这样的:

account: function(section) { 
    if (section) { 
    var section = section.toLowerCase(); 
    } 
    if (app.view) { 
    app.view.undelegateEvents(); 
    } 
    app.view = new AccountView({model: app.user, section: section}); 
}, 

这适用于现在,但会造成内存泄漏吗?

+1

如果你发布你的路由器代码,我可以验证我的直觉,你正在创建重复的视图实例。 –

+0

好的,我发布了路由器的相关部分。 –

回答

6

当我第一次开始使用骨干网时,我的确遇到了同样的问题。就像Peter说的那样,问题在于你有多个View的实例被创建并监听事件。为了解决这个问题,我创建了我最后的骨干工程这一解决方案:

/* Router view functions */ 
showContact:function() { 
    require([ 
     'views/contact' 
    ], $.proxy(function (ContactView) { 
     this.setCurrentView(ContactView).render(); 
    }, this)); 
}, 
showBlog:function() { 
    require([ 
     'views/blog' 
    ], $.proxy(function (BlogView) { 
     this.setCurrentView(BlogView).render(); 
    }, this)); 
}, 


/* Utility functions */ 
setCurrentView:function (view) { 
    if (view != this._currentView) { 
     if (this._currentView != null && this._currentView.remove != null) { 
      this._currentView.remove(); 
     } 
     this._currentView = new view(); 
    } 
    return this._currentView; 
} 

正如你所看到的,它总是删除最后一个视图,并创建一个新的,然后呈现。我还在路由器中添加了一条require语句,因为我不想在路由器中加载所有视图直到它们真正需要。祝你好运。

+0

谢谢!很高兴看到我不是唯一一个处理这个问题的人。这是一个很好的解决方案。 –

+0

@ j-a-x您能否详细介绍如何安排路由器和应用程序文件。 – jeevs

+0

@jeevs对不起人,一会儿还没碰过骨干。我现在转到Angular :) –

0

听起来像您将多个视图实例附加到同一个DOM元素,并且它们都响应事件。您每次浏览时是否在不删除以前的视图的情况下制作新视图?

+0

你可能是对的,虽然我刚刚在创建新视图之前尝试过'app.view.remove()',但是新视图根本没有渲染...... –

+1

那么,你需要渲染并附加它。你的'undelegateEvents'我_think_会好的,但我认为它不是最简单的骨干模式,可以用于你的用例。 –

+0

我绝对乐于接受建议;-) –

0

我有一个动态视图,基于路由器参数在同一元素(约12)内呈现不同的模板。现在,视图呈现的容器在view.render()中定义如下“el:'#some-container'”。当然,如果它存在的话,在创建一个新的或者同一个之前,我必须删除这个视图,以防止僵尸和s#!t。提醒一下,调用view.remove()实际上会从DOM中删除'#some-container',这意味着除了第一次以外,视图没有地方可以渲染。现在有几十种方法可以防止这种情况发生。只是觉得我应该分享以防止任何人需要保存几个小时的研究。