如何在Backbone.js中呈现和附加子视图

内容来源于 Stack Overflow,并遵循CC BY-SA 3.0许可协议进行翻译与使用

  • 回答 (2)
  • 关注 (0)
  • 查看 (11)

initialize : function () {

    this.subView1 = new Subview({options});
    this.subView2 = new Subview({options});
},

render : function () {

    this.$el.html(this.template());

    this.subView1.setElement('.some-el').render();
    this.subView2.setElement('.some-el').render();
}

优点:不必担心在附加的情况下维护正确的DOM顺序。视图是在早期初始化的,因此在Render函数中没有那么多事情要做。

缺点:被迫重新委托Events(),这可能会很昂贵吗?父视图的呈现功能与需要发生的所有子视图呈现都是杂乱无章的。没有能力设置tagName元素,因此模板需要维护正确的标签名。

另一种方式是:

initialize : function () {

},

render : function () {

    this.$el.empty();

    this.subView1 = new Subview({options});
    this.subView2 = new Subview({options});

    this.$el.append(this.subView1.render().el, this.subView2.render().el);
}

优点:你不需要重新委派事件。不需要一个只包含空占位符的模板,并且tagName将返回到由视图定义的位置。

缺点:现在,必须确保按正确的顺序追加内容。父视图的呈现仍然被子视图呈现弄得乱七八糟。

带着onRender活动:

initialize : function () {
    this.on('render', this.onRender);
    this.subView1 = new Subview({options});
    this.subView2 = new Subview({options});
},

render : function () {

    this.$el.html(this.template);

    //other stuff

    return this.trigger('render');
},

onRender : function () {

    this.subView1.setElement('.some-el').render();
    this.subView2.setElement('.some-el').render();
}

优点:子视图逻辑现在与视图的render()方法。

带着onRender活动:

initialize : function () {
    this.on('render', this.onRender);
},

render : function () {

    this.$el.html(this.template);

    //other stuff

    return this.trigger('render');
},

onRender : function () {
    this.subView1 = new Subview();
    this.subView2 = new Subview();
    this.subView1.setElement('.some-el').render();
    this.subView2.setElement('.some-el').render();
}

会保留或添加哪些操作呢?不会做什么呢?

做法摘要:

  • 实例化子视图initialize或在render?
  • 中执行所有子视图呈现逻辑。render或在onRender?
  • 使用setElementappend/appendTo?
提问于
用户回答回答于

在做实际的事件触发(也就是说,不是人为的“onRender“事件),将这些事件绑定到render本身。如果你发现render变得笨重和复杂,你的子视图太少。

...
render: function() {
    $(this.el).html(this.template());
    this.addAll();
    return this;
},
  addAll: function() {
    this.collection.each(this.addOne);
},
  addOne: function(model) {
    view = new Views.Appointment({model: model});
    view.render();
    $(this.el).append(view.el);
    model.bind('remove', view.remove);
}

这只是比第二个示例稍微复杂一些的设置:它们专门设置一组函数,addAlladdOne做肮脏的工作。

用户回答回答于

我通常看到/使用了几种不同的解决方案:

解决方案1

var OuterView = Backbone.View.extend({
    initialize: function() {
        this.inner = new InnerView();
    },

    render: function() {
        this.$el.html(template); // or this.$el.empty() if you have no template
        this.$el.append(this.inner.$el);
        this.inner.render();
    }
});

var InnerView = Backbone.View.extend({
    render: function() {
        this.$el.html(template);
        this.delegateEvents();
    }
});

这与你的第一个示例类似,只做了几处更改:

  1. 附加子元素的顺序
  2. 外部视图不包含要在内部视图上设置的html元素(这意味着您仍然可以在内部视图中指定tagName)。
  3. render()在内部视图的元素被放置到DOM之后调用,如果内部视图的render()方法是根据其他元素的位置/大小(在我的经验中,这是一个常见的用例)将自身放置/调整到页面上。

解决方案2

var OuterView = Backbone.View.extend({
    initialize: function() {
        this.render();
    },

    render: function() {
        this.$el.html(template); // or this.$el.empty() if you have no template
        this.inner = new InnerView();
        this.$el.append(this.inner.$el);
    }
});

var InnerView = Backbone.View.extend({
    initialize: function() {
        this.render();
    },

    render: function() {
        this.$el.html(template);
    }
});

解决方案2看起来可能更干净,但它在我的经验中造成了一些奇怪的事情,并对性能产生了负面影响。

我通常使用解决方案1,原因如下:

  1. 我的许多视图都依赖于已经在DOM中的render()方法
  2. 当重新呈现外部视图时,不必重新初始化视图,重新初始化会导致内存泄漏,并且会导致现有绑定出现异常问题。

如果正在初始化new View()每次render(),则初始化将调用delegateEvents()

扫码关注云+社区