Backbone.js - 移除所有子视图

20

我有一个顶级 PageView,每当路由变化时,它都会重新呈现自身。 我有许多嵌套的子视图嵌入到这个 PageView 中。 如果我要重新呈现 PageView,我需要一并删除/解除所有嵌套的子视图和 PageView 吗?还是只需要删除/解除 PageView? 如果我需要删除/解除所有子视图,最好的方法是什么?


解绑子视图是什么意思?你是指事件吗? - Trevor
4个回答

36
是的,您需要正确地删除和解绑它们: 使用父视图中子视图的数组存储子视图,然后在父视图的close方法中循环遍历该数组并调用子视图的close方法是一种简单的方法。 http://lostechies.com/derickbailey/2011/09/15/zombies-run-managing-page-transitions-in-backbone-apps/
ParentView = Backbone.View.extend({
  initialize: function(){
    this.childViews = [];
  },

  render: {
    for (var i = 0; i < 10; i++){
      var childView = new ChildView();
      // do stuff with the child view
      this.childViews.push(childView);
    }
  },

  close: function(){
    this.remove();
    this.unbind();
    // handle other unbinding needs, here
    _.each(this.childViews, function(childView){
      if (childView.close){
        childView.close();
      }
    })
  }
});

当你准备删除/替换父视图时,请务必调用父视图的close方法。这将确保所有子元素都被正确清理(假设它们都有自己的close方法)。


这真的很长,而且很糟糕!老实说,我从未见过这种情况...你要删除的DOM结构有多大?我唯一的猜测是浏览器太慢了,或者DOM节点集非常大。 - Derick Bailey
1
每个语句末尾都缺少一个 ')'。 - Bjorn
Derick,你对这个问题的看法在过去的一年里有所改变吗?我正在考虑抛出一个全局的“PageChange”事件,然后所有视图都会关闭(包括子视图),但我更倾向于每个页面级别的类型视图调用其所有子视图上的close方法,这是我正在开发的应用程序目前正在做的事情,只是不太一致。 - Cory Danielson
2
我仍然使用这里描述的技术。我已经将其集成到我的Marionette.js框架中,用于Backbone应用程序,因此我不再需要考虑它。 - Derick Bailey
1
从1.1.2版本开始,this.remove()也会解除所有事件的绑定,因此不再需要使用this.unbind()。但是子视图仍然需要关闭... - crazyphoton
显示剩余4条评论

3
一个简单且模块化的类,您可能会发现它很有用。
ContainerView = Backbone.View.extend({
  initialize: function() {
    this.children = [];
  },
  remove: function() {
    Backbone.View.prototype.remove.apply(this, arguments);
    this.removeAllChildren();
  },
  removeAllChildren: function() {
    _.each(this.children, function(view) { view.remove(); });
    this.children = [];
  },
  appendAllChildren: function() {
    _.each(this.children, function(view) { this.$el.append(view.render().$el); }, this);
  }
});

用法:

MyView = ContainerView.extend({
  render: function() {
    this.removeAllChildren();
    this.$el.empty();

    // For each child view...
    // this.children.push(new SomeControl(...));

    this.appendAllChildren();
    return this;
  }
});

2

不必保留子视图数组,可以遍历您的视图的所有属性并查看哪些是Backbone.View的实例;您需要确保为父视图中的每个子视图设置一个属性。

在下面的示例中,将子视图设置为父视图的属性。 我不确定循环遍历所有属性的性能损失会是什么样子,但是,这可能比跟踪单独的数据结构更容易管理子视图。

示例:

var ContextView = Backbone.View.extend({
    initialize: function() {
      // views render themselves via their initialize methods
      this.titlebar = new TitlebarView({el: $("#titlebar")});       
      this.toolbar = new ToolbarView({el: $("#toolbar")});
      this.content = new ContentView({el: $("#content")});
    },
    removeChildViews: function() {      
        for(var prop in this){
            if (this[prop] instanceof Backbone.View) {
                console.log("This is a view: "+ prop + ' in ' + this[prop]);    
            }
        }
    }, 
    render: function() {
        this.$el.html(this.el);
    }
  });

1

有点像Zengineer写的,我喜欢像下面这样全局地修补Backbone.View.remove,这样任何附加在此上的子视图都将被删除。

var originalRemove = Backbone.View.prototype.remove;

Backbone.View.prototype.remove = function ()
{

  for (var view in this){
    if (this[view] instanceof Backbone.View && this[view] != this) {
        this[view].remove();
    } 
  }


  originalRemove.apply(this, arguments);

}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接