javascript - 不可能的 Backbone 僵尸

标签 javascript jquery backbone.js

我现在大部分时间都在尝试调试我的 Backbone 多页面应用程序以摆脱“僵尸”,但不幸的是没有成功。在今天之前,我什至没有意识到我有一个僵尸问题。我做错了什么?

这是我的区域经理:

  var regionManager = (function() {
    var currView = null;
    var rm = {};

    var closeView = function(view) {
      if (view && view.close) {
        view.close();
      }
    };

    var openView = function(view) {
      view.render();
      if (view.onShow) {
        view.onShow();
      }
    };

    rm.show = function(view) {
      closeView(currView);
      currView = view;
      openView(currView);
    };

    return rm;
  })();

这是我的 View 清理功能:

  Backbone.View.prototype.close = function() {
    if (this.onClose) {
      this.onClose();
    }

    if (this.views) {
      _.invoke(this.views, 'close');
    }

    // Unbind any view's events.
    this.off();

    // Unbind any model and collection events that the view is bound to.
    if (this.model) {
      this.model.off(null, null, this);
    }

    if (this.collection) {
      this.collection.off(null, null, this);
    }

    // Clean up the HTML.
    this.$el.empty();
  };

我尝试将 View el 直接附加到 body 并在 View 清理函数中使用 this.remove(); (而不是使用常见的 el: $('#content') 向其附加元素,然后通过 this.$el.empty() 进行清理),但这也不起作用。

这可能与我的“全局事件”有关:

Backbone.Events.on('letterMouseDown', this.letterMouseDown, this);

但我用 onClose 函数来处理它们:

onClose: function() {
  Backbone.Events.off('letterMouseDown');
}

最佳答案

我发现的一个问题是,您的 close 函数永远不会从 View 的 el 中删除事件委托(delegate)者。 View 的事件是通过使用 jQuery 的 on 的委托(delegate)者形式来处理的。将单个事件处理程序附加到 View 的 el。您的 close 会:

this.$el.empty();

但这只会删除内容和附加到该内容的任何事件处理程序,它对直接附加到 this.el 的处理程序没有任何作用。考虑这个最小的例子:

var V = Backbone.View.extend({
    events: {
        'click': 'clicked'
    },
    clicked: function() {
        console.log('still here');
    }
});
var v = new V({ el: '#el' });
v.close();

之后,单击#el 将会在控制台中抛出'still here',即使您认为 View 已完全清理。演示:http://jsfiddle.net/ambiguous/aqdq7pwm/

添加 undelegateEvents调用 close 应该可以解决这个问题。

<小时/>

一般建议:

  1. 不要使用老式的 onoff事件函数,使用listenTostopListening反而。 listenTo 跟踪监听器上的事件,以便以后更轻松地将它们全部删除。

  2. 将您的close简化为:

    Backbone.View.prototype.close = function() {
      if(this.onClose)
        this.onClose();
      if(this.views)
        _.invoke(this.views, 'close');
      this.remove();
    };
    
  3. 不要将 View 绑定(bind)到现有的el。让 View 创建(并拥有)自己的 el 并让调用者将该 el 放入通常的容器中:

    var v = new View();
    container.append(v.render().el);
    

    模式。如果您必须附加到现有的el,那么 View 应该使用标准实现的稍微修改版本覆盖remove:

    remove: function() {
      this.$el.empty();        // Instead of removing the element.
      this.undelegateEvents(); // Manually detach the event delegator.
      this.stopListening();
      return this;
    }
    

关于javascript - 不可能的 Backbone 僵尸,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/33200663/

相关文章:

javascript - ajax 和 javascript 的区别

在 IE 中使用 'not' 的 JQuery 性能问题

javascript - 我可以在不手动跟踪模糊事件的情况下将表单输入绑定(bind)到 Backbone.js 中的模型吗?

backbone.js - 在主干中切换 View 以在页面之间导航 - 正确的方法是什么?

javascript - 重新排列 javascript 对象 - 使用 .sort() 的键不会保留在正在排序的数组上

javascript - Javascript 中的原型(prototype)对象破坏了 jQuery?

css - 当文本框聚焦时阻止 div 向上滑动

javascript - jQuery 自定义菜单 - 添加和删除类 onClick

javascript - 如何从 jQuery 延迟传递参数

javascript - 使用纯 JavaScript 的可拖动列