backbone.js - 集合和视图

13

我知道如何组合一个集合或者单个模型。通常情况下我可以将模型数据显示出来。但是我不太清楚如何获取集合并且将集合中的模型列表进行展示。

我需要遍历整个集合并且逐个渲染每个模型吗? 这部分应该包含在集合的渲染函数中吗?

或者说集合仅仅具有自己的视图,我需要将整个集合的数据填充到视图中吗?

一般而言,展示模型列表的正常方法是什么?

4个回答

13

根据我的经验,最好在收藏视图时引用每个模型的视图。

我目前正在处理的项目中的这段代码应该能帮助你更好地理解:

var MyElementsViewClass = Backbone.View.extend({
    tagName: 'table',

    events: {
        // only whole collection events (like table sorting)
        // each child view has it's own events
    },
    initialize: function() {
        this._MyElementViews = {}; // view chache for further reuse
        _(this).bindAll('add');
        this.collection.bind('add', this.add);
    },
    render: function() {
        // some collection rendering related stuff
        // like appending <table> or <ul> elements

        return this;
    },
    add: function(m) {
        var MyElementView = new MyElementViewClass({
            model: m
        });

        // cache the view
        this._MyElementViews[m.get('id')] = MyElementView;

        // single model rendering
        // like appending <tr> or <li> elements
        MyElementView.render(); 
    }
});
采用这种方法可以更加高效地更新视图(只重新渲染表格中的一行而不是整个表格)。

我建议您将这些MyElementViews缓存到一个集合对象中。 - Raynos
我在尝试让这个工作时遇到了麻烦 - 我理解主要思路,但也许我只是对初始化函数、事件绑定感到困惑。fetch()不会触发'add'事件,对吗?当集合被获取时,视图应该更新,难道不应该有一种方式吗?或者我应该在初始化函数中手动“添加”每个模型? - Matthew
@Raynos,为什么要在一个集合对象中? - pawlik
不用在意那个建议。虽然我认为整个方法应该更加注重集合/模型驱动。 - Raynos
在网上找到了一个非常好的插件/教程,以一种相当优雅的方式实现了这个:http://rickquantz.com/2012/02/rendering-backbone-collections-in-a-view/ - 1nfiniti
1
@pawlik,我无法建议编辑,因为它不足6个字符,但是this._MyElementViews: {};应该是this._MyElementViews = {}; - jds

8
我认为有两种方法可以做到这一点。
  • 对于每个项目使用一个视图,并自己操作DOM。 这就是Todos示例所做的。这是一种不错的方式,因为单个模型项目的事件处理更清晰。您还可以为每个项目使用一个模板。缺点是,您没有整个集合视图的单个模板。
  • 对整个集合使用一个视图。 这里的主要优点是您可以在模板中进行更多的操作。缺点是您没有每个项目的模板,因此如果您有一个异构集合,则需要在集合视图模板代码中进行切换 -- 繁琐。

对于第二种策略,我已经编写了类似以下内容的代码:

var Goose = Backbone.Model.extend({ });

var Gaggle = Backbone.Collection.extend({
   model: Goose;
};

var GaggleView = Backbone.View.extend({
    el: $('#gaggle'),
    template: _.template($('#gaggle-template').html()),
    render: function() {
        $(this.el).html(this.template(this.model.toJSON()));
    }
};

var g = new Gaggle({id: 69);

g.fetch({success: function(g, response) {
    gv = new GaggleView({model: g});
    gv.render();
}});

模板代码应该长这样:
  <script type="text/template" id="gaggle-template">
  <ul id="gaggle-list">
  <% _.each(gaggle, function(goose) { %>
     <li><%- goose.name %></li>
  <% }); %>
  </ul>
  </script>

请注意,我在模板中使用了_函数(非常有用!)。我还使用了“obj”元素,该元素在模板函数中被捕获。这可能有点作弊;传入{gaggle:[...]}可能更好,而且不太依赖于实现。
我认为归根结底答案是:“有两种方法可以做到这一点,但没有一种方法是很好的。”

虽然第二种方法的代码量较少,但我不喜欢集合视图中对集合实例名称的硬编码引用(在AppView.addAll中的Todo)。 - p3drosola
我想这就是需要使用 _.bindAll 的地方。 - p3drosola

3
Backbone的理念是视图渲染是事件驱动的。
视图附加到模型数据更改事件,以便当模型中的任何数据更改时,视图会自动更新。
您应该使用集合来同时操作一组模型。
我建议阅读注释示例

0

我也觉得Backbone框架的这一部分很令人困惑。

这里有一个Todos代码示例。它使用了4个类:

  • Todo(扩展自Backbone.Model)。表示要完成的单个项目。
  • TodoList(扩展自Backbone.Collection)。其“model”属性是Todo类。
  • TodoView(扩展自Backbone.View)。其tagName为“li”。它使用模板来呈现单个Todo。
  • AppView(扩展自Backbone.View)。其元素是“#todoapp”。它没有“model”属性,而是使用名为“Todos”的全局TodoList(不清楚为什么...)。它绑定到Todos上的重要更改事件,当有更改时,它会添加一个单独的TodoView,或者循环遍历所有Todo实例,一次添加一个TodoView。它没有用于呈现的单个模板;它让每个TodoView自己呈现,并且有一个单独的模板用于呈现统计信息区域。

这并不是世界上最好的第一次审查示例。特别是,它没有使用Router类来路由URL,也没有将模型类映射到REST资源。

但是最佳实践似乎是为集合中的每个成员保留一个视图,并直接操作这些视图创建的DOM元素。


1
肯定会遇到相同的问题,试图理解这个。看看这个人的解决方案,它解决了我自己的很多问题:http://rickquantz.com/2012/02/rendering-backbone-collections-in-a-view/ - 1nfiniti

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