backbone学习记录

2014年10月09日

模型、视图、集合和路由器是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({
// Hash maps for routes routes : {
   "" : "index",
   "/teams" : "getTeams",
   "/teams/:country" : "getTeamsCountry",
   "/teams/:country/:name : "getTeam"
   "*error" : "fourOfour"
   	},
index: function(){
   // Homepage 
   	},
getTeams: function() {
   // 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)。

  1. http://www.example.com 触发 index()
  2. http://www.example.com/#/teams 触发 getTeams()
  3. http://www.example.com/#/teams/country1 触发 getTeamsCountry() 传递country1作为参数
  4. http://www.example.com/#/teams/country1/team1 触发 getTeamCountry() 传递 country1 和 team1 作为参数
  5. 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
	}
})

参考链接

访问