65.9K
CodeProject 正在变化。 阅读更多。
Home

BackBone 教程 – 第 5 部分:理解 Backbone.js 集合

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.95/5 (23投票s)

2014年7月21日

CPOL

6分钟阅读

viewsIcon

52897

downloadIcon

675

如何使用 backbone.js 集合来操作一组模型,以及如何使用 RESTful API 轻松获取和保存集合。

引言

在本文中,我们将讨论 backbone.js 的集合(collections)。我们将了解如何使用集合来操作一组模型,以及如何使用 RESTful API 轻松获取和保存集合。

背景

每个应用程序都需要创建模型的集合,这些集合可以被排序、迭代,并在需要时进行筛选和搜索。考虑到这一点,Backbone 也提供了一种集合类型,使得处理模型集合变得相当简单直接。

完整系列链接

  1. BackBone 教程 – 第 1 部分:Backbone.Js 简介[^]
  2. BackBone 教程 – 第 2 部分:理解 Backbone 模型的基础知识[^]
  3. BackBone 教程 – 第 3 部分:关于 Backbone 模型的更多内容[^]
  4. BackBone 教程 – 第 4 部分:使用 HTTP REST 服务对 BackboneJs 模型进行 CRUD 操作[^]
  5. BackBone 教程 – 第 5 部分:理解 Backbone.js 集合[^]
  6. BackBone 教程 – 第 6 部分:理解 Backbone.js 视图[^]
  7. BackBone 教程 – 第 7 部分:理解 Backbone.js 路由和历史记录[^]
  8. BackBone 教程 – 第 8 部分:理解 Backbone.js 事件[^]

Using the Code

让我们开始详细了解 Backbone 集合。

创建一个集合

创建一个 Backbone 集合与创建一个模型类似。我们只需 extend Backbone 的 collection 类来创建我们自己的集合。让我们继续使用之前的例子,我们创建了一个 Book 模型,现在让我们尝试创建一个简单的 BooksCollection

var BooksCollection = Backbone.Collection.extend({
});

这个集合将持有我们在之前文章中创建的 Book 模型。

var Book = Backbone.Model.extend({
    defaults: {
        ID: "",
        BookName: ""
    },
    idAttribute: "ID",
   
    urlRoot: 'https://:51377/api/Books'
});

为集合指定模型

要指定这个集合应该持有哪种模型,我们需要指定/覆盖 collection 类的 model 属性。

var BooksCollection = Backbone.Collection.extend({
    model: Book,
});

一旦我们为 collection 指定了 model 属性,其内部会发生的事情是:每当我们创建这个 collection 时,它内部会创建一个指定模型的数组。然后,对这个 collection 对象的所有操作都会实际作用于那个数组。

实例化一个集合

可以使用 new 关键字来实例化一个 collection。我们可以创建一个空的 collection,然后稍后向其中添加 model 对象,或者在创建 collection 时传入一些 model 对象。

// Lets create an empty collection
var collection1 = new BooksCollection();
//Lets create a pre-populated collection
var book1 = new Book({ ID: 1,  BookName: "Book 1" });
var book2 = new Book({ ID: 2, BookName: "Book 2" });
var collection2 = new BooksCollection([book1, book2]);

向集合中添加模型

要向 collection 添加一个项目,我们可以使用 collection 上的 add 方法。这里需要注意的重要一点是,如果具有相同 id 的项目已存在于 collection 中,add 操作将被忽略。

    var book3 = new Book({ ID: 3, BookName: "Book 3" });
    collection2.add(book3);

现在可能会有一种情况,我们实际上想要更新集合中一个已存在的模型。如果是这样,我们需要在 add 函数中传递 {merge: true} 选项。

var book3 = new Book({ ID: 3, BookName: "Book 3" });
collection2.add(book3);
var book3_changed = new Book({ ID: 3, BookName: "Changed Model" });
collection2.add(book3_changed, { merge: true });

另一个需要考虑的重点是,collection 保存的是实际模型的浅拷贝。因此,如果我们在将一个模型添加到 collection 后更改了它的属性,该属性值在 collection 内部也会发生改变。

此外,如果我们想添加多个模型,可以通过在 add 方法中传递一个模型数组来实现。

var book4 = new Book({ ID: 4, BookName: "Book 4" });
var book5 = new Book({ ID: 5, BookName: "Book 5" });
collection2.add([book4, book5]);

也可以在集合的特定索引处添加模型。要做到这一点,我们需要在 add 选项中传递 {at: location}

var book0 = new Book({ ID: 0, BookName: "Book 0" });
collection2.add(book0, {at:0});

注意pushunshift 函数也可以用来向集合中添加模型。

从集合中移除模型

要从集合中移除模型,我们只需调用集合上的 remove 方法。remove 方法会简单地将该模型从集合中移除。

    collection2.remove(book0);

此外,如果我们想清空模型,可以调用集合上的 reset 方法。

    collection1.reset();

也可以通过在 reset 函数中传递一个模型数组来重置一个集合并用新的模型填充它。

    collection2.reset([book4, book5]); // this will reset the collection and add book4 and book5 into it

注意popshift 函数也可以用来从 collection 中移除 model

获取集合中的项目数量

可以使用 length 属性来获取集合中的项目总数。

    var collection2 = new BooksCollection([book1, book2]);
    console.log(collection2.length); // prints 2

从集合中检索模型

要从特定位置检索模型,我们可以使用 at 函数,并传递一个从 0 开始的索引。

    var bookRecieved = collection2.at(3);

另外,要获取集合中已知模型的索引,我们可以使用 indexOf 方法。

    var index = collection2.indexOf(bookRecieved);

如果我们知道模型的 idcid,我们也可以从集合中检索它。这可以通过使用 get 函数来完成。

    var bookFetchedbyId = collection2.get(2); // get the book with ID=2
    var bookFetchedbyCid = collection2.get("c3"); // get the book with cid=c3

如果我们想遍历集合中的所有模型,我们可以简单地使用经典的 for 循环,或者使用集合提供的 each 函数,它与 underscore.jsforeach 循环非常相似。

for (var i = 0; i < collection2.length; ++i) {
    console.log(collection2.at(i).get("BookName"));
}
collection2.each(function (item, index, all) {
    console.log(item.get("BookName"));
});

监听集合事件

当集合中的项目被添加、移除或更新时,Backbone collection 会触发事件。我们可以通过监听 addremovechange 事件来订阅这些事件。让我们在我们的模型中订阅这些事件,看看如何实现。

var BooksCollection = Backbone.Collection.extend({
    model: Book,
    initialize: function () {
    
        // This will be called when an item is added. pushed or unshifted
        this.on('add', function(model) {
            console.log('something got added');
        });
        // This will be called when an item is removed, popped or shifted
        this.on('remove',  function(model) {
            console.log('something got removed');
        });
        // This will be called when an item is updated
        this.on('change', function(model) {
            console.log('something got changed');
        });
    },
});

Set 函数

set 函数可用于更新一个集合中的所有项目。如果我们使用 set 函数,它会检查所有现有模型和传入 set 的模型。如果在传入的模型中发现任何新模型,它将被添加。如果有些模型不在新的模型列表中,它们将被移除。如果存在相同的模型,它们将被更新。

var collection3 = new BooksCollection();
collection3.add(book1);
collection3.add(book2);
collection3.add(book3);
collection3.set([book1, { ID: 3, BookName: "test sort"}, book5]);

上面显示的 set 函数将为 book2 调用 remove,为 book3 调用 change,为 book5 调用 add。

对集合进行排序

Backbone 会将 collection 中的所有模型保持在排序状态。我们可以调用 sort 函数来强制再次排序,但模型总是以排序后的顺序存储的。默认情况下,这些项目按照它们被添加到 collection 的顺序进行排序。但我们可以通过为我们的 collection 提供一个简单的比较器(comparator)来自定义这种排序行为。

var BooksCollection = Backbone.Collection.extend({
    model: Book,
    
    comparator: function (model) {
        return model.get("ID");
    },
});

这个比较器的作用是,通过指定应该用于排序的属性来覆盖默认的排序行为。我们甚至可以在这个比较器中使用自定义表达式。

使用 HTTP REST 服务获取集合

为了能够从服务器 fetch(获取)collection,我们需要为返回 collection 的 API 指定 url

var BooksCollection = Backbone.Collection.extend({
    model: Book,
 
    url: "https://:51377/api/Books",
});

现在,要从服务器 fetch(获取)collection,让我们调用 fetch 函数。

var collection4 = new BooksCollection();
collection4.fetch();

使用 HTTP REST 服务保存集合

让我们看看如何将集合中的项目保存到服务器上。

var collection4 = new BooksCollection();
collection4.fetch({
    success: function (collection4, response) {
        // fetch successful, lets iterate and update the values here
        collection4.each(function (item, index, all) {
            item.set("BookName", item.get("BookName") + "_updated"); // let's update all book names here
            item.save();
        });
    }
});

在上面的代码中,我们对每个 model 对象调用了 save。这可以通过覆盖 collection 上的 sync 函数,或者为 collection 创建一个包装器模型并使用它来保存数据,从而得到改进。

注意:Web API 代码可以从本系列的前一篇文章中下载。

关注点

在本文中,我们讨论了 Backbone 集合。本文是从初学者的角度撰写的。我希望它能提供有用的信息。

历史

  • 2014年7月21日:初版
© . All rights reserved.