「这是我参与11月更文挑战的第 12 天,活动详情查看:2021最后一次更文挑战」。

前面在《 Ember.js 项目开发之 Ember Data 》介绍了Ember Data,本文将继续介绍模型的定义。

模型是定义呈现给用户的数据的属性和行为的类。如果用户离开应用后再回来(或者刷新页面),他们希望看到的任何东西都应该由模型来表示。

当为应用程序创建一个新模型时,需要在 ​​models​​​ 文件夹下创建一个新文件并从 ​​Model​​​ 扩展。使用 Ember CLI 的生成器命令可以方便地完成这一操作。例如,下面创建一个 ​​person​​ 模型:

ember generate model person复制代码

这将生成以下文件:​​app/models/person.js​

import Model from '@ember-data/model';

export default class PersonModel extends Model {
}

定义模型类后,就可以开始查找并使用该类型的记录。

​Ember Data​​​ 模型通常以单数形式设置(这就是为什么在本文使用​​person​​​而不是​​people​​的原因)

定义属性

生成 ​​person​​ 模型后没有任何属性,下面开始增加一些属性:

import Model, { attr } from '@ember-data/model';

export default class PersonModel extends Model {
@attr firstName;
@attr lastName;
@attr birthday;
}

当将从服务器返回的JSON有效负载转换为记录时,以及在修改记录后序列化记录以保存回服务器时,将使用属性。

可以像使用其他任何属性一样使用属性,包括从​​getter​​函数中使用。

import Model, { attr } from '@ember-data/model';

export default class PersonModel extends Model {
@attr firstName;
@attr lastName;

get fullName() {
return `${this.firstName} ${this.lastName}`;
}
}

Transforms

可能会发现服务器返回的属性类型与要在JavaScript代码中使用的类型不匹配。Ember Data 允许为称为转换的属性类型定义简单的序列化和反序列化方法。可以通过提供转换名称作为方法的第一个参数,来指定要为属性运行转换 ​​attr​​​。Ember Data 支持的属性类型​​string​​​,​​number​​​,​​boolean​​​,和​​date​​,这些类型将值强制转换为与其名称匹配的JavaScript类型。

import Model, { attr } from '@ember-data/model';

export default class PersonModel extends Model {
@attr('string') name;
@attr('number') age;
@attr('boolean') admin;
@attr('date') birthday;
}

日期转换将​​ ISO 8601​​ 字符串转换为JavaScript日期对象。

布尔值转换可以处理 ​​true​​​ 或 ​​false​​​ 以外的值。字符串​​"true"​​​或​​"t"​​​任何大写字母,和​​"1"​​​数字 ​​1​​​ 都将强制转换为 ​​true​​​,反之为 ​​false​​。

转换不是必需的,如果没有指定转换名称,​​Ember Data​​ 将不会对该值进行额外的处理。

自定义Transforms

可以使用 ​​Ember CLI​​​ 的 ​​transform​​ 生成器创建自定义转换:

ember generate transform dollars复制代码

这是一个简单的转换,可在美分和美元之间转换价值。

import Transform from '@ember-data/serializer/transform';

export default class DollarsTransform extends Transform {
deserialize(serialized) {
return serialized / 100; // returns dollars
}

serialize(deserialized) {
return deserialized * 100; // returns cents
}
}

转换有两个功能:序列化 ​​serialize​​​ 和反序列化 ​​deserialize​​。反序列化将值转换为客户端期望的格式。序列化则相反,将值转换为持久层所期望的格式。

以下使用自定义 ​​dollars​​ 转换:

import Model, { attr } from '@ember-data/model';

export default class ProductModel extends Model {
@attr('dollars') spent;
}

选项Options

​attr​​​ 也可以将选项的哈希作为第二个参数。目前唯一可用的选项是 ​​defaultValue​​,它可以使用一个值或一个函数来设置属性的默认值(如果没有提供的话)。

在下面的例子中,定义了 ​​verified​​​ 的默认值为 ​​false​​​ ,而 ​​createdAt​​ 的默认值为模型创建时的当前日期:

import Model, { attr } from '@ember-data/model';

export default class UserModel extends Model {
@attr('string') username;
@attr('string') email;
@attr('boolean', { defaultValue: false }) verified;
@attr('date', {
defaultValue() { return new Date(); }
}) createdAt;
}

Read-only属性

当API返回一个深度嵌套的只读对象或数组时,不需要创建多个具有 ​​attr('hasMany')​​​ 或 ​​attr('belongsTo')​​​ 关系的模型。这可能会导致大量不必要的代码,可以访问模板中的这些对象,而不需要对它们进行转换。这可以通过使用​​ @attr​​ 来完成,而无需指定转换:

import Model, { attr } from '@ember-data/model';

export default class PlaceModel extends Model {
@attr location; // a read-only object
@attr tags; // a read-only array
}

{{@model.location.latitude}}复制代码