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

BackBone 教程 - 第三部分:更多关于 BackBone 模型

starIconstarIconstarIconstarIconstarIcon

5.00/5 (19投票s)

2014年7月16日

CPOL

7分钟阅读

viewsIcon

62136

downloadIcon

904

与 BackBone 模型相关的更多概念

引言

在本文中,我们将探讨更多与 Backbone 模型相关的概念。我们将尝试了解如何覆盖默认的模型行为。我们将研究模型 ID 的重要性,如何验证模型,最后,模型如何本地或在服务器上持久化。

背景

在前面的几篇文章中,我们已经讨论了 Backbone 和 Backbone 模型的基础知识。本文是该系列文章的延续。

完整系列链接

  1. BackBone 教程 – 第一部分:Backbone.Js 简介[^]
  2. BackBone 教程 – 第二部分:理解 Backbone 模型基础[^]
  3. BackBone 教程 – 第三部分:更多关于 Backbone 模型[^]
  4. BackBone 教程 – 第四部分:使用 HTTP REST 服务在 Backbone.Js 模型上进行 CRUD 操作[^]
  5. BackBone 教程 – 第五部分:理解 Backbone.Js 集合[^]
  6. BackBone 教程 – 第六部分:理解 Backbone.Js 视图[^]
  7. BackBone 教程 – 第七部分:理解 Backbone.Js 路由和历史[^]
  8. BackBone 教程 – 第八部分:理解 Backbone.Js 事件[^]

Using the Code

initialize 函数和构造函数

每当我们创建一个模型时,Backbone 都会调用其 initialize 函数。我们可以覆盖此函数为其提供自定义行为。

var Book = Backbone.Model.extend({
    defaults: {
        ID: "",
        BookName: ""
    },
    initialize: function () {
        console.log('Book has been initialized');       
    },
});

因此,当我们创建此对象时,输出将是

内部发生的情况是,每当创建一个 Backbone 模型时,都会调用其构造函数。构造函数将调用 initialize 函数。我们也可以提供自己的构造函数并提供自定义行为。

var Book = Backbone.Model.extend({
    defaults: {
        ID: "",
        BookName: ""
    },
    initialize: function () {
        console.log('Book has been initialized');       
    },
    constructor: function (attributes, options) {
        console.log('Book\'s constructor had been called');
    },
});

创建此模型时的输出

现在,这个构造函数的问题在于,每当创建 Backbone 模型时,都会调用我们的构造函数。但是默认构造函数在对象构造时还会执行许多其他活动,例如调用 initialize 函数。因此,为了确保我们的自定义构造函数能够与所有默认行为协同工作,我们需要让 Backbone 框架知道我们仍然想要默认行为。这可以通过在自定义构造函数末尾调用 Backbone.Model.apply(this, arguments); 来完成。这将确保我们的自定义构造函数被调用,然后默认构造函数应执行的所有其他活动也一并完成。

var Book = Backbone.Model.extend({
    defaults: {
        ID: "",
        BookName: ""
    },
    initialize: function () {
        console.log('Book has been initialized');       
    },
    constructor: function (attributes, options) {
        console.log('Book\'s constructor had been called');
        Backbone.Model.apply(this, arguments);
    },
});

现在输出将是

注意:在大多数实际用途中,覆盖 initialize 函数就足够了。很少需要覆盖构造函数,但如果决定覆盖构造函数,则应按此方式进行。

模型标识符 - id, cid 和 idAttribute

每个模型都需要被唯一标识。为此,Backbone 为我们提供了模型标识符。第一个要看的是 cidcid 或客户端 ID 是由 Backbone 自动生成的,以便每个模型都可以在客户端唯一标识。

var book1 = new Book();
var book2 = new Book();

Backbone 还提供了一个标识符 id 来唯一标识模型实体。这是模型数据实际与服务器同步(即持久化)时用于标识模型的 id。cid 对于调试目的更有用,但 id 属性将决定模型在对模型进行 CRUD 操作时的唯一性。设置和获取 id 属性非常直接。

var book2 = new Book();
book2.id = 3;
console.log(book2.id);

上述代码的输出为:3

此时会有点令人困惑。由于我们的大多数模型都有一个对应于实体主键/唯一标识符的属性,我们是否需要显式地将 id 值设置为该属性。答案是肯定的,也否定的。我们必须以某种方式向 Backbone 模型指示哪个属性应该用作 id,但不必显式设置 id。我们可以使用 idAttribute 来实现这一点。

var Book = Backbone.Model.extend({
    defaults: {
        ID: "",
        BookName: ""
    },
    idAttribute: "ID",
    initialize: function () {
        console.log('Book has been initialized');
    },
    constructor: function (attributes, options) {
        console.log('Book\'s constructor had been called');
        Backbone.Model.apply(this, arguments);
    },
});

在上面的代码中,我们通过指定 idAttribute 来指定 ID 应该用作 id。现在,让我们尝试使用 ID 值创建一个新模型。

var book3 = new Book({ ID: 43 });
console.log(book1.id);

我们可以看到 id 值是从指定的属性中获取的。

因此,这使得 Backbone 模型与服务器端实体协同工作变得更加容易,并使模型标识无缝。

验证模型

当我们处理业务应用程序时,通常需要在持久化数据之前验证模型。Backbone 提供了一种非常简单的方法来验证模型数据。我们只需要实现模型的 validate 函数。

var Book = Backbone.Model.extend({
    defaults: {
        ID: "",
        BookName: ""
    },
    idAttribute: "ID",
    initialize: function () {
        console.log('Book has been initialized');
    },
    constructor: function (attributes, options) {
        console.log('Book\'s constructor had been called');
        Backbone.Model.apply(this, arguments);
    },
    validate: function (attr) {
        if (attr.ID <= 0) {
            return "Invalid value for ID supplied."
        }
    }
});

这里发生的是,每当我们尝试保存模型(我们将在下一节中看到)时,都会调用 Validate 函数。它将检查我们已设置的自定义验证逻辑并验证模型。要测试 validate 方法,我们可以使用模型的 isValid 函数。

var book4 = new Book({ ID: -4 });
var result = book4.isValid(); // false

另一种防止模型属性中出现无效值的方法是在设置模型属性时传递 validate:true。这也将触发 validate 函数。

var book5 = new Book();
book5.set("ID", -1, {validate:true});

这将不会允许设置无效值,即使该值根据我们的自定义逻辑是无效的。

此验证的工作方式是,每当用户选择保存模型时,都会调用 validate 函数。如果存在任何验证错误,则模型保存将失败。或者,用户可以选择在想要限制模型属性中的无效值设置时传递 validate:true。如果我们想在任何特定实例上检查模型的有效性,我们可以使用 isValid 函数进行测试。话虽如此,这里要了解的一个重要事情是,每当我们的验证函数未能验证模型时,Backbone 就会引发一个 invalid 事件。如果我们想监听此事件,可以订阅它。让我们尝试挂接到此事件并查看验证错误。我们将在模型的 initialize 函数中执行此操作。

var Book = Backbone.Model.extend({
    defaults: {
        ID: "",
        BookName: ""
    },
    idAttribute: "ID",
    initialize: function () {
        console.log('Book has been initialized');
        this.on("invalid", function (model, error) {
            console.log("Houston, we have a problem: " + error)
        });
    },
    constructor: function (attributes, options) {
        console.log('Book\'s constructor had been called');
        Backbone.Model.apply(this, arguments);
    },
    validate: function (attr) {
        if (attr.ID <= 0) {
            return "Invalid value for ID supplied."
        }
    }
});

保存模型

Backbone 模型天然支持使用 RESTful Web API 在服务器上保存。要使用 HTTP REST 服务保存模型,我们需要在 Backbone 模型中指定 urlRoot。要实际保存模型,我们可以调用 Backbone 模型上的 savesave 方法将触发验证,如果验证成功,它将尝试识别要执行的操作,即创建或更新,并且基于该操作,它将使用 urlRoot 并调用适当的 REST API 来执行操作。

所以,如果我在本地机器上运行一个服务,我首先需要在我的模型中为该服务指定 urlRoot

var Book = Backbone.Model.extend({
    defaults: {
        ID: "",
        BookName: ""
    },
    idAttribute: "ID",
    initialize: function () {
        console.log('Book has been initialized');
        this.on("invalid", function (model, error) {
            console.log("Houston, we have a problem: " + error)
        });
    },
    constructor: function (attributes, options) {
        console.log('Book\'s constructor had been called');
        Backbone.Model.apply(this, arguments);
    },
    validate: function (attr) {
        if (attr.ID <= 0) {
            return "Invalid value for ID supplied."
        }
    },
    urlRoot: 'https://:51377/api/Books'
});

要使用此服务保存此模型,我可以这样做:

var book = new Book({ BookName: "Backbone Book 43" });
    book.save({}, {
        success: function (model, response, options) {
            console.log("The model has been saved to the server");
        },
        error: function (model, xhr, options) {
            console.log("Something went wrong while saving the model");
        }
    });

save 函数还接受 success 和 error 回调函数,以便可以根据服务器的响应采取适当的操作。

现在,如果我们想将模型保存在本地存储而不是服务器上,我们只需要记住 save 函数实际上调用 sync 函数来实际保存/检索模型信息。因此,如果我们想将模型保存在本地存储中,我们需要覆盖 sync 函数并提供自定义代码以保存在本地存储中。

注意:上面显示的(用于 save 模型的)代码在语法上是正确的,但除非我们在指定的 urlRoot 处运行 REST 服务,否则它将不起作用。在接下来的文章中,我将详细介绍使用 REST 服务保存模型的代码,并附带示例服务和 HTML 代码。

看点

因此,我们看到了有关 Backbone 模型的一些更多细节。我们还没有研究如何将模型本地保存或通过服务保存。也许在我的下一篇文章中,我们将只讨论这个问题。

历史

  • 2014年7月16日:第一个版本
© . All rights reserved.