简体   繁体   English

重新渲染子视图后,骨干事件会多次触发

[英]Backbone events are firing multiple times after re-rendering sub-views

We have a single Backbone view comprised of a sidebar and several sub-views. 我们有一个由侧边栏和几个子视图组成的Backbone视图。 For simplicity, we've decided to have the sidebar and sub-views governed by a single render function. 为简单起见,我们决定让侧边栏和子视图由单个render功能控制。 However, the click .edit event seems to be firing multiple times after clicking on one of the sidebar items. 但是, click .edit其中一个侧边栏项后, click .edit事件似乎会多次触发。 For example, if I start out on "general" and click .edit , then hello fires once. 例如,如果我从“general”开始并单击.edit ,那么hello会触发一次。 If I then click .profile on the sidebar and click .edit again, hello fires twice. 如果我再单击.profile的侧边栏,点击.edit再次, hello闪光两次。 Any ideas? 有任何想法吗?

View 视图

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

Router 路由器

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

Solution

My solution was to change the router to this: 我的解决方案是将路由器更改为:

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

This works for now, but will this create a memory leak? 这现在有效,但这会造成内存泄漏吗?

I had exactly the same problem when I first started using backbone. 当我第一次开始使用骨干时,我遇到了完全相同的问题。 Like Peter says, the problem is that you have more than one instance of the View being created and listening for the event. 就像Peter说的那样,问题在于你创建了多个View实例并正在监听事件。 To solve this, I created this solution in my last backbone project: 为解决这个问题,我在上一个骨干项目中创建了这个解决方案:

/* 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;
}

As you can see, it's always removing the last view and creating a new one, which then renders. 正如您所看到的,它总是删除最后一个视图并创建一个新视图然后呈现。 I also add a require statement in the router because I don't want to have to load all views in the router until they are actually needed. 我还在路由器中添加了一个require语句,因为我不想在路由器中加载所有视图,直到实际需要它们为止。 Good luck. 祝好运。

Sounds like you are attaching multiple view instances to the same DOM element and they are all responding to the events. 听起来您正在将多个视图实例附加到同一个DOM元素,并且它们都响应事件。 Are you making a new view each time you navigate without removing the previous view? 您是在每次导航时创建新视图而不删除上一个视图吗?

I have a dynamic view, that renders different templates inside the same element (about 12), based on router params. 我有一个动态视图,根据路由器参数在同一个元素(大约12个)内呈现不同的模板。 Now, the container in which the view renders, is defined inside the view.render() like so "el: '#some-container'". 现在,视图呈现的容器在view.render()中定义,如“el:'#some-container'”。 Naturally, i have to remove the view if it exists, before creating a new or the same one, to prevent zombies and s#!t. 当然,我必须删除视图,如果它存在,在创建一个新的或相同的,以防止僵尸和s#!t。 Just as a reminder, calling view.remove(), actually removes '#some-container' from the DOM, meaning the view has no place to render in, except for the first time. 提醒一下,调用view.remove()实际上会从DOM中删除“#some-container”,这意味着视图无法呈现,除了第一次。 Now, there are dozens of methods to prevent this from happening. 现在,有许多方法可以防止这种情况发生。 Just thought i should share in case anyone needs to save a few hours of research. 只是想我应该分享以防任何人需要节省几个小时的研究。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM