Skip to content

Instantly share code, notes, and snippets.

@kevinkindom
Last active August 29, 2015 13:59
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save kevinkindom/10831031 to your computer and use it in GitHub Desktop.
Save kevinkindom/10831031 to your computer and use it in GitHub Desktop.
Backbone.js

Backbone.js 简介

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的区别:

database

从图中可以看到数据表中有9条数据,回到Backbone.js中。

每一条数据就相当于一个Model实例。 数据库中有help_category_idnameparent_category_idurl 这4个字段,如果一条新记录所有字段都可以为空,并且如果在空值的情况下有默认值,那么相当于Model中的default属性,用于在实例化时填充默认数据。

而Collection则是这一个数据表,里面包含0个或多个Model对象。

Backbone.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对象的实例化属性

当实例化一个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 的主要介绍如上,如还有不清晰或遗漏的地方再进行补充。

Backbone.Collection

创建一个Collection的时候,一般我们会指定urlmodelinitialize这几个方法,然后根据需要可能还会需要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个方法。

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment