Backbone技术解析

Backbone是一款前端MVC框架,对于前段开发人员,将会产生很多的便利,使得我们的前端代码更容易维护;但是无可否认,使用Backbone进行前端开发无疑增加了前端开发人员的工作量,因为了解并熟悉Backbone的机制是需要时间的。不过清晰的代码逻辑、高维护性依然使得很多项目采用了Backbone框架,对于稍微大一点的项目,前端业务逻辑可能比较复杂,代码组织可能比代码实现更加重要。

当然前端开发框架还有很多,比如更流行的RegularJS,比Backbone拥有更多的用户,不过Bakbone的小巧和灵活性依然是ResgularJS不能比较的。Backbone拥有更多的可能性,所以对于前端开发人员的技术要求更高一点,对于一个初次接触Backbone的童鞋来说,熟悉Backbone机制比什么都重要,不然写出的各种View和绑定事件一定会让你抓狂不已。

不幸的是Backbone没有告诉我们如何组织代码,让很多开发者对于如何加载所需脚本是比较迷茫的,所以将require与Backbone集成起来。require可以帮助我们轻松组织Backbone。

为了方便多个view的加载,我们使用require.js与Backbone集成起来,关于require的内容,在上一章节中介绍过。

首先给大家看一下全球js库和框架的使用比例:

这是通过搜索引擎抓取script标签统计而来的数据,可信度相当高啊,另外,不要迷恋Angular.js,Avalon.js还是挺不错的。

  • 什么是Backbone.js?

Backbone.js是十大JS框架之首,Backbone.js 是一个重量级js MVC 应用框架,也是js MVC框架的鼻祖。它通过Models数据模型进行键值绑定及custom事件处理,通过模型集合器Collections提供一套丰富的API用于枚举功能,通过视图Views来进行事件处理及与现有的Application通过JSON接口进行交互。

简而言之,Backbone是实现了web前端MVC模式的js库

  • 什么是MVC?
    -

MVC:后端服务器首先(过程1)通过浏览器获取页面地址,对网址进行解析,得到视图View给它的一个网址,然后通过控制器controller进行解析,然后去找对应的数据(过程2),找到数据后,再将数据Model返回给控制器(过程3),控制器controller再对数据进行加工,最后返回给视图(过程4),即更新视图View。这种结构在后端是非常清晰且易实现的

  • Backbone中MVC的机制

Backbone将数据呈现为模型, 你可以创建模型、对模型进行验证和销毁,甚至将它保存到服务器。 当UI的变化引起模型属性改变时,模型会触发”change”事件; 所有显示模型数据的视图会接收到该事件的通知,继而视图重新渲染。 你无需查找DOM来搜索指定id的元素去手动更新HTML。 — 当模型改变了,视图便会自动变化。———百度百科

模式:一种解决问题的通用方法

—设计模式:工厂模式、适配器模式和观察者模式

—框架模式:MVC、MVP、MVVM

控制器:通过控制器来连接视图与模型。

MVC模式的思想

就是把模型与视图分离,通过控制器来连接他们

服务器端MVC模式非常容易实现

Model:模型即数据,模型 是所有 js 应用程序的核心,包括交互数据及相关的大量逻辑: 转换、验证、计算属性和访问控制。你可以用特定的方法扩展 Backbone.Model

View:即你在页面上所能看到的视图。每一个单一的数据模型对应一个视图View

web页面本身就是一个很大的view,不太容易做到分离操作,backbone.js适合复杂的大型开发,并为我们解决了这些难题

backbone的模块

backbone有如下几个模块:

Events:事件驱动模块
Model:数据模型
Collection:模型集合器
Router:路由器(对应hash值)
History:开启历史管理
Sync:同步服务器方式
View:视图(含事件行为和渲染页面 相关方法)
集合器Collection是对单独的数据模型进行统一控制

下面我们来详细说一下Backbone中各种常用的机制。


  • Model

Backbone数据模型,是前端操作的分子数据单位,对应后台的一条记录,用来存储实际操作的数据。

define([ "backbone" ], function(Backbone) {

var domain = Backbone.Model.extend({
    defaults : {
        id : null,      // ID
        name : null,    // 名称
        domainCode : null   //组织代码
    }
});
return domain;
});

这里需要依赖的模块是backbone,模型就是扩展Backbone的Model,并增加自己的属性,除此之外,Backbone还提供了关于model的事件监听,比如一下:

var Task = Backbone.Model.extend({
initialize: function () {
    this.on("change:name", function (model) {
        alert("new name is : " + model.get("name"));
    });
}
});

var t = new Task({tid:"3333", name:"oooo", state:"working"});
t.set({name:"xxx"});

绑定了model的change事件,change事件可以指定属性,比如以上就只是绑定了name属性的change事件,在设置model的name的时候触发这个事件;不加的话,就是绑定了整个model的事件,model的任何一个属性改变都会触发这个事件。

Model使用 fetch 方法从后台获取数据:

var currUser = new UserModel();
BackBone.currUser.fetch({
        url : "api/" + sessionId + "/users/currentuser",
        reset : true,
        wait : true,
        success : function(model, data) {},
        error : function(model, data) {
            window.location = "login";
        }
    });

Model用save新增和更新数据

首次保存时(isNew),会采用create方式(HTTP post),已存在的model则只需要update方式(HTTP put)

var p1 = new Person()
p1.save({name: 'Backus', age: 87}) // create
p1.save({name: 'John'}) // update

可以传success和error两个回调函数以处理保存成功与失败的情况

var p1 = new Person()
p1.save({name: 'Backus', age: 87}, {
    success: function() {},
    error: function() {}
})

Model使用destory销毁:

// 1 删除当前model
    this.model.destroy({
            url : "api/" + sessionId + "/schedules/",
            wait : true, 
            success : function(model, data){
            },
            error : function(model, data){
            }
        });

参数说明:

reset : 当模型数据从服务器返回时, 它使用 set来(智能的)合并所获取到的模型, 除非你传递了 {reset: true}, 在这种情况下,集合将(有效地)重置。

wait : 创建一个模型将立即触发集合上的”add”事件, 一个”request”的事件作为新的模型被发送到服务器, 还有一个 “sync” ”事件,一旦服务器响应成功创建模型的时候触发。 如果你想在集合中添加这个模型前等待服务器相应,请传递{wait: true}。

sort : 强制对集合进行重排序。一般情况下不需要调用本函数,因为当一个模型被添加时, comparator 函数会实时排序。要禁用添加模型时的排序,可以传递{sort: false}给add。 调用sort会触发的集合的”sort”事件。


-Collection
-

Collection就是model的集合,需要指明model。

define([ "backbone", "domainModel" ],
    function(Backbone, DomainModel) {

        var collection = Backbone.Collection.extend({
            model : DomainModel
        });

        return collection;
    });

注意define中需要依赖model模块。

collection还提供了诸如比较排序的方法。

var books =new Backbone.Collection(null, {
            model:Book,
            comparator:function(m1,m2){
                var price1 = m1.get('price');
                var price2 = m2.get('price');

                return price1 > price2 ? 1:0;
            }    

        });

Collection获取数据

var collection = new UserCollection();
this.collection.fetch({
            url : "api/" + sessionId + "/users" ,
            reset : true,
            wait : true,
            success : function(collection, data) {

            },
            error : function(collection, data) {
                window.location = "login";                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                           
            }
        });

Collection新增model

this.collection.create(schedule, {
                url:"api/"+ sessionId + "/schedules/" + this.templateId+"/appointments",
                success : function(model , data){
                },
                error : function(model , data){

                },
                sort : true,
                wait : true
            });

collection还提供了快速查找,需要说明的是backbone强依赖于underscore,underscore提供了几十种高效精简的工具方法,比如collection的很多快速查找,遍历等方法都是基于underscore的。

遍历collection

this.collection.each(function(model){
} , this);

each的第二参数可以省略,当需要确定工作空间的时候,需要指明;
比如这里,each中的this,就是第二个参数确定的工作空间,如果不指明第二个参数的话,each中的this,不等同于each外的this.

快速查找

var friends = new Backbone.Collection([
  {name: "Athos",      job: "Musketeer"},
  {name: "Porthos",    job: "Musketeer"},
  {name: "Aramis",     job: "Musketeer"},
  {name: "d'Artagnan", job: "Guard"},
]);

var musketeers = friends.where({job: "Musketeer"});

alert(musketeers.length);

或者使用find

var ret = this.collection.find(function(model , index){
if (model.get("name) = "vence")
    return true;
});

find得到的返回就是查找的model对象,如果查找不到就是null;

  • View
    -

Backbone 视图几乎约定比他们的代码多 — 他们并不限定你的HTML或CSS, 并可以配合使用任何JavaScript模板库。 一般是组织您的接口转换成逻辑视图, 通过模型的支持, 模型变化时, 每一个都可以独立地进行更新, 而不必重新绘制该页面。我们再也不必钻进 JSON 对象中,查找 DOM 元素,手动更新 HTML 了,通过绑定视图的 render 函数到模型的 “change” 事件 — 模型数据会即时的显示在 UI 中。

SearchView = Backbone.View.extend({

initialize: function(){

    this.render();

},

render: function() {

    //使用underscore这个库,来编译模板

    var template = _.template($("#search_template").html(),{});

    //加载模板到对应的el属性中

    this.el.html(template);

},

events:{  //就是在这里绑定的

    'click input[type=button]' : 'doSearch'  //定义类型为button的input标签的点击事件,触发函数doSearch

},

doSearch: function(event){
    alert("search for " + $("#search_input").val());
}

});

var searchView = new SearchView({el: $("#search_container")});
  • Event
    -

Events 是一个可以融合到任何对象的模块, 给予 对象绑定和触发自定义事件的能力. Events 在绑定之前 不需要声明, 并且还可以传递参数. 比如:

var object = {};

_.extend(object, Backbone.Events);

object.on("alert", function(msg) {
  alert("Triggered " + msg);
});

object.trigger("alert", "an event");

时间监听ListenTo

让 object 监听 另一个(other)对象上的一个特定事件。不使用other.on(event, callback, object),而使用这种形式的优点是:listenTo允许 object来跟踪这个特定事件,并且以后可以一次性全部移除它们。callback总是在object上下文环境中被调用。

this.listenTo(model, 'change', view.render);        // 监听模型变化事件
this.listenTo(collection, "sync" , this.handleSync);    // 监听collection获取事件

事件解绑

从 object 对象移除先前绑定的 callback 函数。如果没有指定context(上下文),所有上下文下的这个回调函数将被移除。如果没有指定callback,所有绑定这个事件回调函数将被移除;如果没有指定event,所有事件的回调函数会被移除。

// Removes just the `onChange` callback.
object.off("change", onChange);

// Removes all "change" callbacks.
object.off("change");

// Removes the `onChange` callback for all events.
object.off(null, onChange);

// Removes all callbacks for `context` for all events.
object.off(null, null, context);

// Removes all callbacks on `object`.
object.off();

基于Backbone自定义全局事件

this.listenTo(Backbone, "Schedule:AddSchedule", this.handleAddSchedule);

解绑
Backbone.off(“Schedule:AddSchedule”);

使用Backbone进行前端开发,一定要注意培养一个良好的开发习惯,比如谁产生,谁销毁,事件绑定和解绑,绑定Dom事件的时机等等,具体我将在下一节进行探讨

本站总访问量