呃……前面那个坑还没填完,因为我又改变了一些想法还在试验中。
这是一个小坑,是两个月前给新团队的小伙伴们入门 Ember Data 时写的大纲,这两个月下来我发现还是挺有用的,先放出来以备后面挖大坑用……注意,这份大纲编写的时候 Ember Data 才刚刚 2.0 beta,到今天已经有了一些变化,而且官方的 API 文档做了很多补全或修正,所以实际应用还是要多看文档,以它为准。
DS.Store
DS.Model
的数据实体,为的是让这样的数据实体可以和 Handlebars 模版进行数据绑定DS.Model
DS.InternalModel
,专门用来处理 Ember Data 内部的数据模型,但不应用来开发 Ember 应用里的数据模型。这是因为 DS.Model
产生的数据实体是有数据绑定等能力的,适合于 UI 编程(与模版视图进行数据绑定);而 DS.InternalModel
处理的数据实体都是纯 JavaScript 对象,只适合 Ember Data 内部(不需要和模版视图进行数据绑定)。也因此,DS.InternalModel
要比 DS.Model
快些DS.Snapshot
DS.RootState
currentState
属性,它显式的追踪着数据实体在任意时间点下的状态。比如说一条刚创建并且没有保存(即提交至后端)的数据实体,其状态是 root.loaded.created.uncommitted
等等currentState
属性,数据实体对这些事件如何反应取决于当前所处的状态。在不同的状态下,一些事件是无效的并且会抛出相应的异常(可用来追踪非法操作,比如说标注为 删除状态
的数据实体不能不访问或修改等等)RootState
的子状态。比方说,一条数据实体可以从 root.deleted.uncommitted
状态转换至 root.deleted.inFlight
状态等等。如果一个子状态没有响应的事件回调函数,状态管理会尝试去调用它所有的父级状态的事件回调函数来处理它,直到根级状态。stateName
属性来获取当前状态的完整路径。例如:record.get('currentState.stateName')
DS.Model
的状态其本身是“无状态的”,这个意思是说:分层式的状态数据结构在全局中只有一份(类似单例对象),每一个状态所指向的都是这个不可改变且全局共享的数据结构(immutable and global shared data structure)一个状态可能实现零或多个事件和旗标
transitionTo
方法来完成为了便于理解,举一个例子来说明,想象当前有这样一个状态结构:
接着,如果调用 record.transitionTo('inFlight')
,那么状态将会转换至 created.inFlight
;如果调用 record.transitionTo('updated.inFlight')
,那么状态会转换至 updated.inFlight
。
切记!状态转换必须发生在事件回调函数内,永远不要在事件回调函数外调用 transitionTo
方法;如果你确实需要,就创建一个新的自定义事件并发送给状态管理机制(于是这个事件的回调函数就能用来调用 transitionTo
方法了)
旗标就是一系列的布尔类型的属性,为了让你方便的查询数据实体当前的状态(而不是解析路径字符串)。比方说,虽然你可以这样做:
let statePath = record.get('stateManager.currentPath')
if (statePath === 'created.inFlight') {
doSomething()
}
但是,这样做会更方便:
if (record.get('isNew') && record.get('isSaving')) {
doSomething()
}
以上例子也暗示了一件事:旗标与状态并非一一对应的(虽然有时候是),一个状态可能是由多个旗标共同定义的。
如果一个状态没有设置对应的旗标,那么旗标的值会继承父级状态对应的旗标,或者是之前的状态设置的值。
以下是默认的旗标,它们的说明可以在 DS.Model
的文档里找到。如果你需要定义新的旗标,需要在 DS.Model
里定义新的属性。
DS.Transform
根据官方文档的描述,Ember Data 默认允许我们定义四种数据类型的数据属性,它们分别是:string
number
boolean
和 date
。有时候我们需要自定义类型的数据属性,我们可以利用 DS.Transform
接口来进行扩展。它的简单用法如下:
// app/transforms/temperature.js
import DS from 'ember-data'
// 转换 JSON 里的摄氏度数,变成应用里的华氏度数
export default DS.Transform.extend({
deserialize: function(serialized) {
return (serialized * 1.8) + 32
},
serialize: function(deserialized) {
return (deserialized - 32) / 1.8
}
})
// app/models/requirement.js
import DS from 'ember-data'
export default DS.Model.extend({
name: DS.attr('string'),
temperature: DS.attr('temperature') // 实际应用
})
DS.Adapter
findRecord()
createRecord()
updateRecord()
deleteRecord()
findAll()
query()
findMany()
方法来优化你的 AdapterDS.RESTAdapter
,适用于标准的 REST API Service,你可以重载其中的方法来适应你的(非标准的)REST API ServiceDS.JSONAPIAdapter
,JSON API 规范 是基于 REST 架构的新一代的标准,它定义和规范了开发基于 JSON 的 REST API 的一系列标准和实践准则DS.DebugAdapter
,这是 Ember Data 内部用于调试的适配器,通常不需要考虑它DS.BuildURLMixin
和 DS.EmbeddedRecordsMixin
这两个 Mixins 用于为 Adapter 实现两种功能:
具体用法可以参考 DS.RESTAdapter
或 DS.JSONAPIAdapter
。
DS.Serializer
normalizeResponse()
serialize()
normalize()
(可选)DS.JSONSerializer
,以及对应 REST 和 JSON API 适配器的 DS.RESTSerializer
和 DS.JSONAPISerializer
。需要定义适合自己 API Service 的序列器就可以参考以上的例子或者直接继承 DS.JSONSerializer
举一个常见的例子,假设你有这样的 data model:
App.User = DS.Model.extend({
name: DS.attr(),
friends: DS.hasMany('user'),
house: DS.belongsTo('location'),
})
此时如果直接使用 DS.JSONSerializer
,那么请求或响应获得的 JSON 数据应该是这样的:
{
id: 1,
name: 'Sebastian',
friends: [3, 4],
links: {
house: '/houses/lefkada'
}
}
这是很常规的 JSON 数据格式,如果你的服务器与此不符,那么你可以扩展 DS.JSONSerializer
来重新定义。
DS.Errors
DS.Errors
是 Ember Data 提供的异常和错误处理的基础类DS.Model
都有一个 errors
属性,其值就是一个 DS.Errors
的实例对象,可以用来显示服务端返回的验证错误信息DS.ActiveModelAdapter
(以前版本里自带的适配器,用于适配 Rails 框架,现已被抽取出去变成了独立的 Addon)实现了这一套机制,可以自动处理 Rails 返回的错误信息。如果你要定义适合自己 API Service 的错误信息,可以参考它的实现DS.Errors
以期提供更多的默认类,文档尚未补全