Javascript 在重新渲染子视图后,主干事件将触发多次

Javascript 在重新渲染子视图后,主干事件将触发多次,javascript,backbone.js,Javascript,Backbone.js,我们有一个单一的主干视图,由一个侧栏和几个子视图组成。为了简单起见,我们决定让边栏和子视图由一个render函数管理。但是,click.edit事件似乎在单击其中一个侧边栏项目后多次触发。例如,如果我从“常规”开始,然后单击.edit,那么hello会触发一次。如果我随后单击侧栏上的.profile,然后再次单击.edit,hello将触发两次。有什么想法吗 查看 events: { "click .general": "general", "click .profile": "prof

我们有一个单一的主干视图,由一个侧栏和几个子视图组成。为了简单起见,我们决定让边栏和子视图由一个
render
函数管理。但是,
click.edit
事件似乎在单击其中一个侧边栏项目后多次触发。例如,如果我从“常规”开始,然后单击
.edit
,那么
hello
会触发一次。如果我随后单击侧栏上的
.profile
,然后再次单击
.edit
hello
将触发两次。有什么想法吗

查看

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});
},

现在可以这样做了,但这会造成内存泄漏吗?

听起来像是将多个视图实例附加到同一个DOM元素,它们都在响应事件。是否每次导航时都要创建一个新视图而不删除以前的视图?

我第一次开始使用主干时遇到了完全相同的问题。正如Peter所说,问题在于您有多个视图实例正在创建并侦听事件。为了解决这个问题,我在上一个主干项目中创建了这个解决方案:

/* 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语句,因为我不想在实际需要之前加载路由器中的所有视图。祝你好运。

我有一个动态视图,根据路由器参数在同一个元素(大约12个)内呈现不同的模板。现在,视图在其中渲染的容器在view.render()中定义,如“el:”#some container“。当然,在创建新的或相同的视图之前,我必须删除该视图(如果存在),以防止僵尸和s#!T提醒一下,调用view.remove()实际上从DOM中删除了“#某个容器”,这意味着除了第一次,视图没有地方可以渲染。现在,有几十种方法可以防止这种情况发生。我想我应该分享一下,以防有人需要节省几个小时的研究时间。

如果你发布你的路由器代码,我可以验证我的直觉,你正在创建重复的视图实例。好的,我发布了路由器的相关部分。你可能是对的,尽管我刚刚尝试了
app.view.remove()
在创建新视图之前,但新视图根本不会渲染…嗯,您需要渲染它并附加它。您的
undelegateEvents
我认为可以,但我不认为这是最简单的主干模式,可以适用于您的用例。我当然愿意接受建议;-)我认为路由器操作视图的基本模式应该是构造、渲染、附加、移除、冲洗和重复。但脊梁是灵活的,所以做你认为是健全的。谢谢!很高兴看到我不是唯一一个处理这个问题的人。这是一个很好的解决方案。@j-a-x您能告诉我更多关于您如何安排路由器和应用程序文件的信息吗?@jeevs抱歉,好久没有接触主干网了。我现在开始有棱角了:)