模型、视图、集合和路由器是Backbone框架中的主要组件。
应用场景
backbone最适合的应用场景是单页面应用,并且页面上有大量数据模型,模型之间需要进行复杂的信息沟通。Backbone在这种场景下,能很好的实现模块间松耦合和事件驱动。
路由器
传统ajax与浏览器历史
ajax是无页面刷新的,页面的url没有办法改变,这样就无法支持浏览器的前进和后退(流量购项目踩了大坑!!!)。 传统的ajax请求有如下问题:
1、可以无刷新改变页面内容,但无法改变页面URL(有复制链接给他人的需求等无法实现)
2、为了更好的可访问性,内容发生改变后,通常改变URL的hash(散列片段)
3、hash的方式不能很好的处理浏览器的前进、后退等问题
4、进而浏览器引入了onhashchange的接口,不支持的浏览器只能定时去判断hash是否改变
5、但这种方式对搜索引擎很不友好 我们可以发现新浪微博的部分区域是无页面刷新的,但是它的**url却可以变化**,实现了浏览器的前进后退,那是因为HTML5里引用了新的API,history.pushState和history.replaceState,他们可以操作浏览器历史,并且改变当前页面的URL.
Backbone.Router和Backbone.history
我们回到Backbone提供的路由器。
Backbone 提供一个称为路由器(版本 0.5 前称之为控制器)的组件来路由客户端状态。路由器可以扩展 Backbone.Router 函数,且包含一个散列映射(routes 属性)将状态与活动关联起来。当应用程序达到相关状态(相当于书签)时,会触发一个特定活动。
//示例
App.Routers.Main = Backbone.Router.extend({
"" : "index",
"/teams" : "getTeams",
"/teams/:country" : "getTeamsCountry",
"/teams/:country/:name : "getTeam"
"*error" : "fourOfour"
},
// Homepage
},
// List all teams
},
getTeamsCountry: function(country) {
// Get list of teams for specific country
},
getTeam: function(country, name) {
// Get the teams for a specific country and with a specific name
},
fourOfour: function(error) {
// 404 page
}
});
当 URL 碰到类似下面情况时,会调用这 5 个活动(index、getTeams、getTeamsCountry、getTeamCountry 和 fourOfour)。
- http://www.example.com 触发 index()
- http://www.example.com/#/teams 触发 getTeams()
- http://www.example.com/#/teams/country1 触发 getTeamsCountry() 传递country1作为参数
- http://www.example.com/#/teams/country1/team1 触发 getTeamCountry() 传递 country1 和 team1 作为参数
- http://www.example.com/#/something 触发 fourOfour()以作*使用。
要启动 Backbone,先实例化页面加载的路由器,并通过指令 Backbone.history.start() 方法监视散列片段中的任何变更。
//示例
$(function(){
var router = new App.Routers.Main();
Backbone.history.start({pushState : true});
})
//当实例化路由器时,会生成 Backbone.history 对象;它将自动引用 Backbone.History 函数。Backbone.History 负责匹配路由和 router 对象中定义的活动。start() 方法触发后,将创建 Backbone.history 的 fragment 属性。它包含散列片段的值。该序列在根据状态次序管理浏览器历史方面十分有用。用户如果想要返回前一状态,单击浏览器的返回按钮。
大体感觉
Backbone的路由器,就是为了无刷新页面改变url,支持浏览器的前进后退操作便于历史记录的管理。跟html5提供的history.pushState和history.replaceState接口相关
模型和集合
模型将数据(通常是来自服务器的数据)存储在键值对中。
###Backbone.Model 创建
App.Models.Team = Backbone.Model.extend({
defaults : {
// default attributes
}
//Domain-specific methods go here
});
###模型实例化和 get/set 方法
// "name" attribute is set into the model
var team1 = new App.Models.Team({
name : "name1"
});
console.log(team1.get("name")); // prints "name1"
// "name" attribute is set with a new value
team1.set({
name : "name2"
});
console.log(team1.get("name")); //prints "name2" ###更改 App.Models.Team 模型中的事件处理程序
App.Models.Team = Backbone.Model.extend({
initialize : function(){
this.bind("change", this.changed);
},
changed : function(){
alert("changed");
}
}); ###在模型对象上调用 save 方法 Backbone 的另一个优势是易于**通过Ajax交互与服务器进行通信**。在模型上调用一个save()方法会通过REST JSON API异步**将当前状态保存到服务器**
model.save(); ###模型对象的 Fetch() 方法 当需要从服务器检索一个模型时,请求一个Read活动并使用一个 Ajax GET 请求。这类请求使用fetch()方法。要**确定导入模型数据或者从中取出模型数据的服务器的位置**: 如果模型属于一个 collection,那么集合对象的url属性将是该位置的基础,并且该模型 ID(不是cid)会被附加以构成完整的 URL。 如果模型不是在一个集合中,那么该模型的 urlroot 属性被用作该位置的基础
var teamNew = new App.Models.Team({
urlRoot : '/specialTeams'
});
teamNew.save(); // returns model's ID equal to '222'
teamNew.fetch(); // Ajax request to '/specialTeams/222' ###模型的验证方法validate()
App.Models.Team = Backbone.Model.extend({
validate : function(attributes){
if (!!attributes && attributes.name === "teamX") {
// Error message returned if the value of the "name"
// attribute is equal to "teamX"
return "Error!";
}
});
视图和客户端模板
Backbone 视图
Backbone视图可以扩展Backbone.View函数并显示模型中存储的数据。一个视图提供一个由el属性定义的 HTML 元素。该属性可以是由 tagName、className 和 id 属性相组合而构成的,或者是通过其本身的 el 值形成的。
App.Views.Teams = Backbone.View.extend({
el : 'UL.team-list'
});
// In the following view, el value is 'div.team-element'
App.Views.Team = Backbone.View.extend({
className : '.team-element',
tagName : 'div'
});
Backbone 视图中的模型属性
一个视图必须与一个模型相关联!!!!!视图就是为了渲染数据的
App.Views.Team = Backbone.View.extend({
...
model : new App.Models.Team
}); ### Render() 方法 重写render()方法和逻辑来显示DOM元素(由el属性引用的)中的模型属性
App.Views.Team = Backbone.View.extend({
className : '.team-element',
tagName : 'div',
model : new App.Models.Team
render : function() {
// Render the 'name' attribute of the model associated
// inside the DOM element referred by 'el'
$(this.el).html("<span>" + this.model.get("name") + "</span>");
}
}); ### 使用 _.template() 函数的视图
App.Views.Team = Backbone.View.extend({
className : '.team-element',
tagName : 'div',
model : new App.Models.Team
render : function() {
// Compile the template
var compiledTemplate = _.template($('#teamTemplate').html());
// Model attributes loaded into the template. Template is
// appended to the DOM element referred by the el attribute
$(this.el).html(compiledTemplate(this.model.toJSON()));
}
}); ### Render() 方法绑定到模型变更事件 Backbone中**最有用且最有趣**的一个功能是将render()方法绑定到模型的变更事件中
App.Views.Team = Backbone.View.extend({
model : new App.Models.Team,
initialize : function() {
this.model.bind("change", this.render, this);
}
})
//当模型发生更改时,会自动触发 render() 方法,从而节省数行代码 ### _.bindAll()
App.Views.Team = Backbone.View.extend({
initialize : function() {
_.bindAll(this, "render");
this.model.bind("change", this.render);
}
})
事件属性
App.Views.Team = Backbone.View.extend({
className : '.team-element',
tagName : 'div',
events : {
"click a.more" : "moreInfo"
},
moreInfo : function(e){
// Logic here
}
})