今天我们来谈谈Backbone.js MVC 中的 M
, Model是backbone的核心部分,包含着页面展示内容的数据,还有围绕着数据操作的各种 转换,校验,计算 ,权限控制,服务端交互等等操作,你可以通过 Backbone.Model.extend()
生成你的model , 当然生成的model也可以作为一个基类去向下扩展更多的model
1
2
3
4
5
6
7
| var People = Backbone.Model.extend({
});
var Man = People.extend({
});
|
Backbone.Model Api
Backbone.Model 提供了大量方法用于实现一个Model的基本操作,当然其中最基本的还是基于 Backbone.Events
的事件机制,在Model的attributes发生变化的时候,相应的 change:attr
事件会被触发,下面是提供的API:
其中有对数据进行服务端操作的方法:
- sync : 包装了
Backbone.sync
,xhr
的基类
- fetch : 用于从服务端获取数据
- save : 向服务端持久化数据
- destroy: 从服务端删除数据
model中数据操作的方法:
- get : 从
attributes
中获取数据
- set : 向
attributes
中设置数据
- escape : 对数据进行编码 ,使用的是
underscore
的 _.escape
- has :
attributes
中有无对应数据
- unset : 从
attributes
中删除数据
- clear : 清空
attributes
数据
- changed : 与上个状态(执行过
set
,unset
),相比变化的值
- toJSON : 将
attributes
序列化成一个对象
- parse : 当设置项
parse
为真的时候,初始化/set/unset/fetch
等数据操作中会对目标数据进行一个解析返回解析后的对象,此方法为空方法,需要重写覆盖
- hasChanged : 与上个状态(执行过
set
,unset
),相比是否发生过变化
- changeAttributes : 与上个状态(执行过
set
,unset
),相比发生的所有值
- previous : 前一状态 (执行过
set
,unset
),该属性对应的值
- previousAttributes : 与上个状态(执行过
set
,unset
),发生过变化对象的前一个状态的所有值
model中数据校验的方法:
- validate:用于对
model
中数据进行校验,需要重写覆盖默认方法
- validationError : 返回最近一个
invalid
时返回的值
- isValid : 调用
_validate
方法
下面会针对一些重点的api进行讲解:
构造函数
1
2
3
4
5
6
7
8
9
10
11
12
13
|
var Model = Backbone.Model = function(attributes, options) {
var attrs = attributes || {};
options || (options = {});
this.cid = _.uniqueId('c');
this.attributes = {};
if (options.collection) this.collection = options.collection;
if (options.parse) attrs = this.parse(attrs, options) || {};
attrs = _.defaults({}, attrs, _.result(this, 'defaults'));
this.set(attrs, options);
this.changed = {};
this.initialize.apply(this, arguments);
};
|
构造函数主要对初始化的数据和选项进行设置,然后会对生成一个唯一的cid
用于标示model
,如果options
中的parse
为true
,那么会对初始化数值通过parse
方法进行一个解析,调用set
方法,所有的初始值会被存入attributes
中,调用initialize
初始化方法 。model
的初始化就完成了。
set
model.set(attributes, [options])
set
方法会将值设置进入attribute
中,设置时如果设置了slient
为true
,会触发相应的 change:attr
的事件,最后统一触发change
事件,set方法部分代码如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
| set: function(key, val, options) {
//......
// key值可以是键值对,也可以是一个字符串,将赋值传入attrs属性中
if (typeof key === 'object') {
attrs = key;
options = val;
} else {
(attrs = {})[key] = val;
}
// ....
//对设置的值进行校验
if (!this._validate(attrs, options)) return false;
unset = options.unset; // unset为true时会删除设置的值,unset方法就是通过 set(key,val,{unset:true})去实现的
//当对象正在被被设置的时候,不给 previousAttributes 赋值
if (!changing) {
this._previousAttributes = _.clone(this.attributes);
this.changed = {};
}
current = this.attributes, prev = this._previousAttributes;
//如果对Id进行了设置,则对对象的id属性也进行改变
if (this.idAttribute in attrs) this.id = attrs[this.idAttribute];
//进行 设置或者是删除操作
for (attr in attrs) {
val = attrs[attr];
if (!_.isEqual(current[attr], val)) changes.push(attr);
if (!_.isEqual(prev[attr], val)) {
this.changed[attr] = val;//为model的changed进行设置
} else {
delete this.changed[attr];
}
unset ? delete current[attr] : current[attr] = val;//如果unset被设置成true了,则进行删除操作
}
//在silent不为false 的情况下,进行change:attr事件发送
if (!silent) {
if (changes.length) this._pending = options;
for (var i = 0, l = changes.length; i < l; i++) {
this.trigger('change:' + changes[i], this, current[changes[i]], options);
}
}
//触发change事件
if (changing) return this;
if (!silent) {
while (this._pending) {
options = this._pending;
this._pending = false;
this.trigger('change', this, options);
}
}
this._pending = false;
this._changing = false;
return this;
}
|
set
的整个流程就是 对传入的数值进行处理,变成一个键值对,然后对数值进行校验,检查正确性,然后开始进行设置操作,设置时检查数值时候是发生改变的,如果有则加入一个 changeed
的对象中,然后检查unset
的值,进行相应的添加更新删除操作。然后依次触发change:attr
和change
事件。
save
model.save([attributes], [options])
save方法用于向客户端持久化数据,会根据数据的不同和配置的不同选择使用create,update或者是patch,并且触发 sync 事件,以下为部分代码:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
| save: function(key, val, options) {
// ......
//当设置了wait属性true的时候 , save方法先不执行set方法(不触发change事件),只执行validate
if (attrs && !options.wait) {
if (!this.set(attrs, options)) return false;
} else {
if (!this._validate(attrs, options)) return false;
}
//如果wait为true,设置this.attributes
if (attrs && options.wait) {
this.attributes = _.extend({}, attributes, attrs);
}
// .....
var model = this;
var success = options.success;
options.success = function(resp) {
// Ensure attributes are restored during synchronous saves.
model.attributes = attributes;
var serverAttrs = model.parse(resp, options);
//如果wait为true , 那么会在请求返回之后才进行set操作
if (options.wait) serverAttrs = _.extend(attrs || {}, serverAttrs);
if (_.isObject(serverAttrs) && !model.set(serverAttrs, options)) {
return false;
}
if (success) success(model, resp, options);
//触发 sync 事件
model.trigger('sync', model, resp, options);
};
//生成XHR onerror 回调函数
wrapError(this, options);
//选择方法
method = this.isNew() ? 'create' : (options.patch ? 'patch' : 'update');
if (method === 'patch') options.attrs = attrs;
xhr = this.sync(method, this, options);
// Restore attributes.
if (attrs && options.wait) this.attributes = attributes;
//返回xhr对象
return xhr;
}
|
save
中最需要注意的就是 wait
的设置,当wait
为真的时候,save
返回会在xhr
返回之后再执行set
操作,而不是在xhr
之前就进行set
操作,因此change
事件的触发时机也就不同了。
之前说过整个Backbone都是通过事件串联起来的,所以对于事件触发时机的了解和把握是非常重要的,不然会在开发过程中导致一些奇怪的问题出现。