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事件的时机等等,具体我将在下一节进行探讨