Backbone.js 高度依赖 underscore.js,轻度依赖jQuery,如有必要可以使用zepto.js来置换jQuery。
Backbone.js主要由下面几大类方法:
- Event
- Model
- Collection
- View
- Router
- History
以上方法除了Event本身外,其他所有类都组合了Event,拥有Event所有的方法。
下面主要来看看Model和Collection两个数据方法。
首先要说明Model和Collection的区别
从一张数据库的截图来说明Model和Collection的区别:
从图中可以看到数据表中有9条数据,回到Backbone.js中。
每一条数据就相当于一个Model实例。 数据库中有
help_category_id
、name
、parent_category_id
、url
这4个字段,如果一条新记录所有字段都可以为空,并且如果在空值的情况下有默认值,那么相当于Model中的default属性,用于在实例化时填充默认数据。而Collection则是这一个数据表,里面包含0个或多个Model对象。
创建Model,一般我们只需要指定其defaults、url、方法即可,如果需要构造函数,则传递initialize方法即可,如:
var Books = Backbone.Model.extend({
url: 'get_data.php',
defaults: {
isbn: '',
title: 'sample',
price: '',
publication: '',
pages: ''
},
initialize: function(){
//类的构造方法
}
});
var book1 = new Books;
// 这时我们创建了一个空的数据,打印book1时可以看到attributes里除了title属性为"sample"外,其他属性全部为空。
// 为了设置属性我们可以这么做:
book1.set({isbn: '9787208120952', title: '自画像', price: '25', publication: '2014-4', pages: '128'});
// 也可以单独对一个字段进行设置
book1.set('price', '30');
// 甚至可以在Model实例化的时候进行设置,如:
var book2 = new Books({isbn: '9787115283993', title: 'Node.js开发指南', price: '45', publication: '2012-7', pages: '178'});
使用Model时,得注意以下几个问题:
- 使用set方法是可以设置defaults里不存在的数据。
- Model实例化后再进行set时,会触发Model的
change
事件,如果不想让Model触发change
事件,可以在set时传递{slient: true}
,既:book1.set('price', '40', {slient: true});
。 - 为Model指定defaults时,如果参数是一个object对象,那么该对象是会被共享到所有实例中的,为了避免这个问题,我们可以传递一个function来返回一个object来解决,下面是一个简单的范例:
// 使用object做为参数
var myModel = Backbone.Model.extend({
defaults: {
foo: 'hello',
bar: new Date()
}
});
var model1 = new myModel;
// 这里等待几秒钟后再创建另外一个Model,
var model2 = new myModel;
// 这时输出两个model的bar属性,发现这两个的时间是完全一样的。
console.log(model1.get('bar'));
console.log(model2.get('bar'));
为了避免这个问题,我们可以传递一个function来解决,修改上面的代码为:
// 使用function做为参数
var myModel = Backbone.Model.extend({
defaults: function(){
return {
foo: 'hello',
bar: new Date()
};
}
});
var model1 = new myModel;
// 这里等待几秒钟后再创建另外一个Model,
var model2 = new myModel;
// 现在输出两个model的bar属性,会发现两个时间是自己被实例化时的时间
console.log(model1.get('bar'));
console.log(model2.get('bar'));
Model具体的方法,可以查看官方手册,已经非常明细,值得说明的方法有下面几个:
- fetch
- save
- destroy
上面3个方法都会触发change
事件,并且save和destroy会以restful api的方式去请求服务器的,这点务必注意。
当实例化一个Model对象时,约会包括以下属性:
- _changing: Boolean
- events: Object
- _pending: Boolean
- _previousAttributes: Object
- attributes: Object
- changed: Object
- cid: String
这里我挑主要的说:
events 默认是没有该对象的,只有当model实例注册了一个以上的事件监听,才会出现该方法,events是一个对象,完整的记录了监听事件的列表。
_previousAttributes 该对象仅记录上一次修改的完整信息。
attributes 该对象就是该model上的数据,通常我们取值是通过model.get方法来获取,但也可以通过该属性获得model的完整数据。
changed 记录最近一次修改的信息,仅记录单条修改记录,注意他跟_previousAttributes
的区别。
cid model的唯一id,以c开头,后面跟数字,数字从1开始累加。
Backbone.Model 的主要介绍如上,如还有不清晰或遗漏的地方再进行补充。
创建一个Collection的时候,一般我们会指定url
、model
、initialize
这几个方法,然后根据需要可能还会需要parse
方法。
我们就从这几个方法来入手,看看下面一段代码:
// 先创建一个model
var Books = Backbone.Model.extend({
defaults: {
isbn: '',
title: 'sample',
price: '',
publication: '',
pages: ''
}
});
// 再来创建一个Collection
var BookShelf = Backbone.Collection.extend({
url: 'get_books.php',
model: Books,
initialize: function(){
},
parse: function(result){
// 处理服务器返回的数据,格式化成我们需要的类型
//注意这里需要手动调用一次reset方法。
this.reset(result);
return result;
}
});
var bs1 = new BookShelf;
好了,现在我们拥有了一号书架bs1
方法了,但目前该书架上没有任何图书,我们得往上添加一些书籍。
// 接上面的代码
var book1 = new Books({isbn: '9787208120952', title: '自画像', price: '25', publication: '2014-4', pages: '128'});
var book2 = new Books({isbn: '9787115283993', title: 'Node.js开发指南', price: '45', publication: '2012-7', pages: '178'});
bs1.add([book1, book2]);
// 这时候我们的书架上应该有2本书了
console.log(bs1.models);
但是很快我们就发现,如果需要一条条的去手写 var bookx = new Books
来实例化不同的书,然后再添加到Collection中去,这将会是一场灾难。
于是乎,Collection的fetch
方法就派上用场了,fetch
方法用于从Collection指定的url上获取数据,并填充到Collection中。
如果我们的服务器接口返回的数据如下(get_books.php):
[
{isbn: '9787208120952', title: '自画像', price: '25', publication: '2014-4', pages: '128'},
{isbn: '9787115283993', title: 'Node.js开发指南', price: '45', publication: '2012-7', pages: '178'}
]
上面的代码只需要改为:
// 接上面的代码
bs1.fetch();
// 这时候我们的书架上应该有2本书了
console.log(bs1.models);
这样我们就可以快速从服务器拉回数据合集。
最后来说说Collection的model属性把,根据一开始介绍我们知道Collection相当于数据库中的一个表,Collection的数据实现是基于Model的,如果我们不指定model,那么他会自动指向Backbone.Model,如果指定则使用我们制定好的Model,但指定model有什么好处呢?还记得一开始数据库部分说的缺省值把?没错,如果用我们指定的Model的话,从服务器拉回的数据如果某些字段与Model不匹配的话,则会自动使用我们Model里提供的缺省值来提供填充。并且,Model我们是可以后期扩充一些内置方法来使用的。
如果我们从接口上返回的数据并不是一个数组,既没有length属性,则需要注意了,还是用上面的代码来解释: 数据接口(get_books.php)返回的数据如下:
{
status: 200,
message: '',
data: [
{isbn: '9787208120952', title: '自画像', price: '25', publication: '2014-4', pages: '128'},
{isbn: '9787115283993', title: 'Node.js开发指南', price: '45', publication: '2012-7', pages: '178'}
]
}
然后我们通过下面代码获取数据并填充到Collection:
// 接上面的代码
bs1.fetch();
// 这时候我们发现根本没有任何数据被添加到合集上
console.log(bs1.models);
造成这个问题的原因就是返回的对象没有length方法,合集根本不知道如何添加数据。
这个时候一开始定义的parse方法就派上用场了,我们重新定义BookShelf
方法
var BookShelf = Backbone.Collection.extend({
url: 'get_books.php',
model: Books,
initialize: function(){
},
parse: function(result){
var ret = [];
// 重新格式化数据,处理后的结果如::
// {isbn: '9787208120952', title: '自画像', price: '25', publication: '2014-4', pages: '128', message: '', status: 200}
_.each(data['data'], function(val, key){
ret.push(_.extend(val, {message: data['message'], status: data['status']}));
});
this.reset(ret);
return ret;
}
});
var bs1 = new BookShelf;
这个时候我们再从服务器拉回数据:
// 接上面的代码
bs1.fetch();
// 这时候我们的合集就成功添加了服务器上的2条数据。
console.log(bs1.models);
上面就大致把Collection部分介绍完了,下面贴几个地址:
内置的事件监听列表:http://backbonejs.org/#Events-catalog
Backbone.js为Backbone.Collection提供了28个迭代方法,详情请查看这个网址:http://backbonejs.org/#Collection-Underscore-Methods
Backbone.js的restful接口方式列表:
function method url create POST /collection read GET /collection[/id] update PUT /collection/id delete DELETE /collection/id
目前还有Backbone.View、Backbone.Router、Backbone.History没有讲到,但这3个方法比较简单,后面会通过一些实际应用来解释到这3个方法。