Backbone.js: 通过模板嵌套视图

18

使用模板技术,是否有技术上的可能性将视图嵌套在一起,就像这样:

<%= new PhotoCollectionView({model:new PhotoCollection(model.similarPhotos)}).render().el) %>

我也可以将所有的东西放在render方法中,但使用模板可以提供更多的灵活性和布局空间。

我尝试了上述的变量,但屏幕上显示的只是[HTMLDivElement]

如果我尝试仅提取其中的HTML,使用jQuery的HTML方法,我可以得到渲染后的结果,但发现打印出来的DOM节点与视图所持有的参考不同,因为无法使用视图实例与那些DOM节点进行任何交互。例如,如果在视图内部使用$(this.el).hide(),将不会发生任何事情。

如果有合适的方法,请问应该怎么做?


1
我不确定这种技术在技术上是否可行,但我建议不要使用它,因为模板应该只包含简单的条件语句,而不包含任何应用程序逻辑。应用程序逻辑应保留在您的视图中。这样,就有明确的关注点分离,您的应用程序将更易于维护。 - Johnny Oshika
你可以使用React.js嵌套视图。 - Alexander Mills
5个回答

29

通常我首先呈现父视图。然后我使用 this.$('selector') 方法来查找一个子元素,作为子视图的 el。

以下是完整示例:

var ChildView = Backbone.View.extend({
  //..
})

var ParentView = Backbone.View.extend({
  template: _.template($('#parent-template').html()),
  initialize: function() {
    _.bindAll(this, 'render');
  }
  render: function() {
    var child_view = new ChildView({ el: this.$('#child-el') }); //This refers to ParentView. 
    return this;
  }
});

var v = new ParentView();
v.render(); 

嗯,是的...最终我也做了同样的事情。 - user802232
6
这似乎有点低效。每次渲染父组件时,你都在重新初始化子视图。 - Alessandro Giannone
5
同意Alessandro的观点。除了低效之外,每次渲染父视图时,子视图中的动态状态也会丢失。请查看Backbone.Subviews,这是一个现成的极简解决方案。 - Brave Dave
2
你应该在initialize中创建子视图,并将其存储为父视图的属性。然后在父视图的render函数中调用子视图的render方法。 - michael.orchard

14

被接受的答案存在一个主要缺陷,即每次渲染ChildView时都会重新初始化。这意味着你将失去状态,并且可能需要在每次渲染时重新初始化复杂的视图。

我在这里写了一篇关于此的博客:http://codehustler.org/blog/rendering-nested-views-backbone-js/

总之,我建议使用类似以下的代码:

var BaseView = Backbone.View.extend({

    // Other code here...

    renderNested: function( view, selector ) {
        var $element = ( selector instanceof $ ) ? selector : this.$el.find( selector );
        view.setElement( $element ).render();
    }
});

var CustomView = BaseView.extend({

    // Other code here...

    render: function() {
        this.$el.html( this.template() );
        this.renderNested( this.nestedView, ".selector" );
        return this;
    }
});

如果你不想要,就无需扩展Backbone视图,renderNested方法可以放置在任何位置。

使用上述代码,现在可以在初始化方法中初始化ChildView,然后在调用render()时简单地渲染它。


2

看看Backbone.Subviews混合模式。它是一个极简的混合模式,用于管理嵌套视图,并且不会在每次渲染父级视图时重新初始化子视图。


1

我不知道在模板内部怎么做,但我以前用表格和列表做过。在外部模板中,只需有存根:

<script type="text/template" id="table-template">
    <table>
        <thead>
            <th>Column 1</th>
        </thead>
        <tbody>
        </tbody>
    </table>
</script>

对于每个单独的项目:

<%= field1 %>

然后在您的渲染方法中,只需呈现单独的项目并将它们附加到tbody元素即可...


-1
每次渲染都初始化一个新的对象,这个决定在我看来非常低效。
特别是这个:
render: function() {
    var child_view = new ChildView({ el: this.$('#child-el') }); //This refers to ParentView. 
    return this;
  }

理想情况下,父级的渲染应该是这样的
render: function() {
   this.$el.html(this.template());
   this.childView1.render();
   this.childView2.render();
}

并且子元素的创建应该只在初始化父元素时发生:

initialize: function() {
       this.childView1 = new ChildView1(selector1);
       this.childView2 = new ChildView2(selector2);
} 

问题在于在渲染父模板之前我们没有选择器1和选择器2。这就是我现在卡住的地方 :)


1
这似乎并没有真正回答问题,尽管建议听起来合理。一定要确切地回答“问题”! - random_user_name

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