首页
学习
活动
专区
工具
TVP
发布
社区首页 >问答首页 >如何在Backbone.js中呈现和附加子视图

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

Stack Overflow用户
提问于 2012-02-14 12:00:32
回答 10查看 72.7K关注 0票数 133

我有一个嵌套的视图设置,它可以深入到我的应用程序中。有一堆方法我可以想到初始化,渲染和附加子视图,但我想知道常见的做法是什么。

下面是我想到的几个

代码语言:javascript
复制
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顺序。视图是在早期初始化的,所以在渲染函数中没有那么多事情要一次完成。

缺点:您被迫重新委托costly (),这可能很昂贵?父视图的渲染函数被需要进行的所有子视图渲染弄得乱七八糟?您不能设置元素的tagName,因此模板需要维护正确的tagNames。

另一种方式:

代码语言:javascript
复制
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事件:

代码语言:javascript
复制
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事件:

代码语言:javascript
复制
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();
}

我在所有这些示例中混合和匹配了一堆不同的实践(很抱歉),但是您会保留或添加哪些实践呢?还有什么是你不会做的?

实践总结:

  • 实例化initializerender
  • Perform中的子视图render中或onRender
  • Use setElementappend/appendTo

中的所有子视图呈现逻辑

EN

回答 10

Stack Overflow用户

发布于 2012-06-23 00:20:48

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

解决方案1

代码语言:javascript
复制
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. 外部视图不包含要在内部视图上设置的tagName元素(这意味着您仍然可以在内部视图的元素被放入DOM之后调用内部view)
  3. render()中的tagName,如果内部视图的render()方法根据其他元素的位置/大小在页面上放置自身/调整自身大小)

会很有帮助

解决方案2

代码语言:javascript
复制
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. 当外部视图重新呈现时,视图不需要重新初始化,重新初始化会导致内存泄漏,还会导致现有绑定的异常问题

请记住,如果每次调用render()时都要初始化new View(),则该初始化无论如何都会调用delegateEvents()。因此,正如您所表达的,这不一定是一个“骗局”。

票数 58
EN

Stack Overflow用户

发布于 2012-02-14 12:43:53

这是一个长期存在的问题,在我的经验中,这个问题并没有一个令人满意的答案。我和你一样沮丧,特别是因为尽管这种用例很常见,但指导太少了。也就是说,我通常会使用类似于你的第二个例子的东西。

首先,我会立即排除任何需要您重新委托事件的事情。Backbone的事件驱动视图模型是它最关键的组件之一,仅仅因为你的应用程序很重要就失去了这个功能,这会给任何程序员留下不好的印象。所以从第一点开始。

关于你的第三个例子,我认为它只是绕过了传统的渲染实践,并没有增加太多的意义。也许,如果您正在进行实际的事件触发(即,不是人为的"onRender“事件),那么将这些事件绑定到render本身可能是值得的。如果您发现render变得笨拙和复杂,那么您的子视图太少了。

回到你的第二个例子,这可能是三害中较小的一个。下面是摘自的示例代码,可以在我的PDF版本的第42页找到:

代码语言:javascript
复制
...
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,用于完成繁琐的工作。我认为这种方法是可行的(我当然会使用它);但它仍然留下了奇怪的回味。(请原谅所有这些舌头比喻。)

关于以正确的顺序添加的观点:如果您严格地添加,当然,这是一个限制。但一定要考虑所有可能的模板方案。也许您实际上想要一个占位符元素(例如,一个空的divul),然后您可以replaceWith一个包含相应子视图的新(DOM)元素。追加并不是唯一的解决方案,如果你那么关心它,你当然可以绕过排序问题,但如果它让你绊倒,我可以想象你有一个设计问题。请记住,子视图可以有子视图,如果合适的话,它们应该有子视图。这样,您就有了一个相当不错的树状结构:每个子视图按顺序添加其所有子视图,然后父视图添加另一个子视图,依此类推。

不幸的是,解决方案#2可能是您希望使用开箱即用主干的最好方案。如果你对第三方库感兴趣,我已经研究过的(但实际上还没有时间)是Backbone.LayoutManager,它似乎有一种更健康的添加子视图的方法。然而,即使是他们在类似的问题上也有recent debates

票数 31
EN

Stack Overflow用户

发布于 2014-04-03 07:06:35

令人惊讶的是,这还没有被提及,但我会认真考虑使用Marionette

它为主干应用程序增加了更多的结构,包括特定的视图类型(ListViewItemViewRegionLayout),添加了适当的Controller等等。

这里有the project on Github和一个很棒的guide by Addy Osmani in the book Backbone Fundamentals,可以帮助你入门。

票数 6
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/9271507

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档