Backbine.js實戰第六章----檢視

我叫阿狸貓發表於2014-11-09

6.1 檢視基礎

   與模型和集合物件相類似,在定義一個檢視之前,需要構建一個檢視類。在構建類時,可以設定el屬性關聯DOM中的元素;也可以指定與檢視相關的模型和集合類名,實現各個類之間物件的資料互相訪問,下面逐一進行詳細的介紹。

6.1.1 定義檢視物件

    定義一個檢視物件的方法十分簡單,先通過extend方法構建一個檢視類,再通過關鍵字new的方法例項化檢視物件,在物件中可以呼叫檢視類中的方法。定義過程如下程式碼所示。

var testview = Backbone.View.extend({
	//構建類的邏輯結構
});
//根據構建的類例項化一個test檢視物件
var test = new testview();

    在上述程式碼中,先構建一個名為testview的檢視類,然後以例項化的方式定義一個名為test的檢視物件,這是定義檢視物件最基本的框架。因為檢視的主要功能是將資料渲染至頁面中,因此,在檢視中必須能訪問DOM元素,而要實現這一要求,只需要在構建檢視類時新增DOM元素屬性即可。接下來通過一個簡單示例來進行介紹。

    示例6-1 通過檢視物件新增DOM元素

1.功能描述

    通過定義的檢視物件新增一個DOM元素,並設定該元素的類別名稱。在瀏覽器中執行該頁面時,將在頁面中顯示“backbone是構建前端MVC的利器”字樣。

var testview = Backbone.View.extend({
	id:"show",
	className:"cls_6",
	render:function(content){
		this.el.innerHTML = content;
		document.body.appendChild(this.el);
	}
});
var test = new testview();
test.render("backbone是構建前端MVC的利器");


2.原始碼分析

    在上述頁面檔案的JavaScript程式碼中,為了動態建立一個DOM元素,首先定義id和className屬性,分別對應元素的ID和樣式屬性名稱。這些屬性還包括tagName和attributes,前者為新元素的名稱,如果不設定,則為div元素;後者則是一個物件,它可以設定該元素的其他屬性值,這些新設定的屬性都會在元素新增時一起生效,程式碼如下。

...省略部分程式碼

attributes:{

    title:"測試",

    style:"border:solid 1px #555"

}

...省略部分程式碼

    為了動態設定新新增元素中顯示的內容,需要過載檢視類提供的render函式。在過載過程中重新渲染檢視中的內容,將內容引數content作為新新增元素this.el的innerHTML屬性值,即設定元素顯示的內容,並呼叫append方法將新新增元素追加到body元素中。

    最後,當例項化一個名為test檢視物件,並呼叫物件的render方法過載物件內容時,將向頁面的body元素新增一個設定了內容的div元素,頁面效果如上圖所示。

    上述示例演示的是動態增加一個DOM元素,並將該元素追加至頁面中,其實也可以通過在構建檢視類時設定el屬性訪問頁面中的元素,再通過render方法設定元素中顯示的內容。如果採用這種方法實現示例6-1中的功能,修改程式碼如下。

<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
<script src="../script/jquery-1.11.1.js"></script>
<script src="../script/underscore.js"></script>
<script src="../script/backbone.js"></script>
<style type="text/css">
	.cls_6{
		font-size:12px;
	}
</style>
</head>
<body>
	<div id="show" class="cls_6"></div>
	<script type="text/javascript">
		var testview = Backbone.View.extend({
			el:"#show",
			render:function(content){
				this.el.innerHTML = content;
			}
		});
		var test = new testview();
		test.render("backbone是構建前端MVC的利器");
	</script>
</body>
</html>
   上述程式碼相對於示例6-1首次編寫的程式碼更簡潔,它通過設定el屬性值指定檢視物件在元素中對應的DOM元素。檢視中el屬性值是一個字串形式的元素選擇器,在例項化過程中,檢視內部會通過該選擇器獲取指定的DOM元素物件,並重新儲存至el屬性中。因此在檢視內部,可以通過thi.el的方式訪問這個DOM元素物件。

    每個檢視都會有一個el屬性,用來儲存獲取的DOM元素物件。通常情況下,檢視物件的全部操作都應該在這個元素物件內進行,這樣便於頁面的整體渲染和子集元素的操作。如果沒有設定該屬性,框架會自動生成一個空值的div元素,並將該元素物件設定為el屬性值。

6.1.2 檢視物件訪問模型物件

   嚴格來說,檢視物件通常是接收集合物件返回的資料集,並將資料在頁面中進行渲染,並不直接訪問模型物件。但是,也能直接訪問模型物件,實現的方式是:在例項化檢視物件時,通過設定model屬性值與需要訪問的模型物件進行關聯,關聯之後,在檢視類的內部能以this.model的方式進行訪問。接下來通過一個簡單示例進行介紹。

    示例6-2 通過檢視物件新增DOM元素

1.功能描述

    通過定義的檢視物件,獲取一個例項化模型物件的全部內容值,並將該值以字元的形式顯示在頁面指定的元素中。

var student = Backbone.Model.extend({
	defaults:{
		Code:"",
		Name:"",
		Score:750
	}
});
var stus = new student({
	Code:"10107",
	Name:"皮卡丘",
	Score:750
});
var stusview = Backbone.View.extend({
	el:"#show",
	render:function(){
		this.el.innerHTML = JSON.stringify(this.model);;
	}
});
var stuv = new stusview({model:stus});
stuv.render();

2.原始碼分析

    在本例項的JavaScript程式碼中,首先構建一個student模型類,並例項化一個模型物件stus,用於檢視物件的呼叫。然後,構建一個 stuview檢視類,在構建檢視類中設定el屬性,並過載render方法。在過載過程中,通過this.model方式獲取關聯的模型物件,通過stringify方法將模型物件轉換成字串內容,並將內容顯示在頁面指定的元素中。

    最後,為了關聯模型物件,在例項化檢視物件時一定要新增model模型屬性,並將該屬性的值設定為需要關聯的模型物件名稱,再呼叫檢視物件render方法,將關聯後的模型物件內容顯示在頁面中,最終實現的頁面效果如上圖所示。


6.1.3 檢視物件訪問集合物件

    與訪問模型物件類似,也可以通過檢視物件直接訪問集合物件。實現的方法是:在例項化檢視物件時,將collection屬性值設定為關聯的集合名稱,在構建檢視類時,可以採用this.collection的方式獲取被關聯集合物件。接下來通過一個簡單示例來進行介紹。

    示例6-3 檢視物件訪問集合物件

1.功能描述

    通過定義的檢視物件獲取一個例項化集合物件中全部模型資料的內容值,通過遍歷的方式將這些值以字元的形式顯示在頁面指定的元素中。

var stumodels = [{
	Code:"10101",
	Name:"劉真真",
	Score:530
},{
	Code:"10102",
	Name:"張明基",
	Score:460
},{
	Code:"10103",
	Name:"劉真真",
	Score:530
},{
	Code:"10104",
	Name:"周小敏",
	Score:500
},{
	Code:"10105",
	Name:"陸明明",
	Score:300
}];
var stulist = new Backbone.Collection(stumodels);
var stuview = Backbone.View.extend({
	el:"#show",
	render:function(){
		var curlist = this.collection.models;
		for(var i=0;i<curlist.length;i++){
			this.el.innerHTML += JSON.stringify(curlist[i])+"<br/>";
		}
	}
});
var stuv = new stuview({collection:stulist});
stuv.render();

2.原始碼分析

    在本示例的JavaScript程式碼中,首先定義一個用於填充集合物件的陣列物件stumodels,再以例項化的形式將stumodels物件作為實參定義一個名為stulist集合物件,此時,新定義的集合物件包含了陣列物件stumodels中全部的資料。

    構建集合類時,在過載render方法過程中,以this.collection方式獲取關聯的集合物件,並將該物件的models屬性內容儲存在curlist中,以遍歷的方式獲取models屬性中每個模型資料的內容,並以字元的形式顯示在頁面指定的元素中。

    在例項化檢視物件stuv時新增collection屬性,並將該屬性值設定為已定義的集合物件stulist,從而實現兩個物件的關聯。當檢視物件stuv呼叫render進行過載時,以this.collection方式獲取的集合物件就是被關聯的stulist集合物件。



6.2 檢視中的模板

    在構建檢視類時,雖然可以十分方便地訪問DOM元素,但如果DOM元素過多或存在一定的邏輯性,且這些元素不經常變更。要在JavaScript程式碼中拼接這樣的DOM元素是一件非常複雜的事情,為解決這個問題,可以引入檢視中的模板。

    檢視中的模板分為兩個部分:

    第一部分是在頁面中使用<script>元素進行定義。在定義時,只要將<script>元素的type屬性設定為“text/template”,表名該元素包含的程式碼區域都為模板區。在模板區中,採用<%=變數名稱%>的形式定義變數,並且可以處理業務邏輯。然後,在JavaScript程式碼中通過字典的方式給變數傳值。

    第二部分是在JavaScript程式碼中,通過.template()函式訪問頁面中定義的模板內容,當過載模板內容時,可以通過字典的形式向模板中傳遞變數對應的值。

    接下來通過幾個完整的示例詳細介紹檢視中模板的使用方法。

6.2.1 處理邏輯的模板

    使用<script>元素定義的頁面模板區中,在<%= >區域內,“<% %>”表示區別於其他的HTML元素的特殊符號,“=”表示取值符號,不可缺少。<%= %>區域內的變數會在呼叫模版時,被以字典方式傳入的對應值所取代,如果是字元內容則原樣輸出。並且<%= %>區域內還支援簡單的JavaScript語句。接下來通過一個簡單示例進行介紹。

    示例6-4 處理邏輯的模板

1.功能描述

    在頁面中,使用<script>標記定義一個模板區和一個用於顯示模板區內容的<div>元素。當模板區變數score大於600時,<div>元素顯示”優秀“,否則顯示”及格“。

<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
<script src="../script/jquery-1.11.1.js"></script>
<script src="../script/underscore.js"></script>
<script src="../script/backbone.js"></script>
<style type="text/css">
	body{
		font-size:13px;
	}
	div{
		width:260px;
		padding:5px;
	}
</style>
</head>
<body>
	<div id="score"></div>
	<script type="text/template" id="score-tpl">
		<%= score>600?"優秀":"及格"%>
	</script>
</body>
<script type="text/javascript">
	var stuview = Backbone.View.extend({
		el:$("#score"),
		initialize:function(){
			/*
			 * 呼叫_.template函式獲取指定ID號的頁面模板中的內容,
			 * 並將該內容賦予檢視本身的template屬性。
			 * 這一操作表示頁面的模板已與檢視類相關聯。
			 */
			this.template = _.template($("#score-tpl").html());
		},
		render:function(pscore){
			this.$el.html(this.template({score:pscore}));
		}
	});
	var stuv = new stuview();
	stuv.render(600);
</script>
</html>

2.原始碼分析

    在本示例中,首先在頁面中定義一個ID號為“score”的<div>元素,用於顯示經過邏輯處理後的模板內容,並使用<script>元素定義一個模板。在模型的<%= %>區域中,根據變數score的值,顯示“優秀”或“及格”字樣。

    在構建檢視類時,將el的屬性值設定成ID號為“score”的<div>元素,表明本次的檢視操作都在該元素中顯示。此外,在檢視類的建構函式initialize中,呼叫_.template()函式獲取指定ID號的頁面模板中的內容,並將該內容賦予檢視本身的template屬性。這一操作表示頁面的模板已與檢視類相關聯,可以在檢視物件的render過載方法中,採用this.template的方式訪問頁面中的模板。在訪問時,還可以以字典的形式替換模板中對應的變數值。

    接下來例項化一個名為“stuv”的檢視物件,並呼叫該物件的render方法過載頁面中的模板。在過載時,將600作為實參傳給模板中對應的變數score,並將該變數值與600進行比較,返回“及格”字樣,最後將該返回的內容顯示在ID號為“score”的頁面元素中。



6.2.2 顯示多項內容的模板

    上一節中介紹了檢視中的模板如何顯示有邏輯的變數內容,而在實際的專案開發過程中,檢視中的模板常用於顯示一些與經常變化、有一定排列格式的多項內容,這些多項內容中的變數命名可以與模型物件的各屬性名稱相對應,這樣的命名方式便於將獲取的模型物件轉換成JSON格式後直接傳遞給檢視模板中的對應變數,這種方式的程式碼也更加簡潔、安全、高效。接下來通過一個簡單示例進行介紹。

    示例6-5 顯示多項內容的模板

1.功能描述

    在頁面中,使用<script>標記定義一個包含多項變數內容的模板區和一個用於顯示模板區內容的<ul>元素。當例項化一個檢視物件並過載物件的render方法時,將獲取的模型物件內容直接通過檢視中的模板顯示在頁面的<ul>元素中。

<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
<script src="../script/jquery-1.11.1.js"></script>
<script src="../script/underscore.js"></script>
<script src="../script/backbone.js"></script>
<style type="text/css">
	body{
		font-size:13px;
	}
	div{
		width:260px;
		padding:5px;
	}
</style>
</head>
<body>
	<ul id="ulshowstus"></ul>
	<script type="text/template" id="stus-tpl">
		<li>編號:<%=Code%></li>
		<li>姓名:<%=Name%></li>
		<li>分數:<%=Score%></li>
	</script>
</body>
<script type="text/javascript">
	var student = Backbone.Model.extend({
		defaults:{
			Code:"",
			Name:"",
			Score:0
		}
	});
	var stus = new student({
		Code:"10107",
		Name:"皮卡丘",
		Score:750
	});
	var stuview = Backbone.View.extend({
		el:$("#ulshowstus"),
		initialize:function(){
			this.template = _.template($("#stus-tpl").html())
		},
		render:function(){
			this.$el.html(this.template(this.model.toJSON()));
		}
	});
	var stuv = new stuview({model:stus});
	stuv.render();
</script>
</html>

2.原始碼分析

    在本示例程式碼中,首先在頁面中定義一個用於檢視傳遞資料的檢視模板stus-tpl,在該模板中根據顯示格式的要求新增<li>元素作為子元素項,並以顯示模型物件的各屬性名稱作為在子元素項中的變數名。這種命名方式便於模型物件在JSON格式化後直接將資料傳遞給檢視模板中的各個對應變數,操作十分方便。此外,在頁面中還定義一個名為ulshowstus的<ul>元素,用於顯示接收資料之後的檢視模板內容。

    在構建檢視類的過程中,宣告el屬性所指定的DOM元素物件為ID號為ulshowstus的<ul>元素。在重構函式initialize中,將頁面中的模板內容賦予檢視本身的template屬性。在檢視物件的render過載方法中,先將獲取的模型物件內容進行JSON格式化,再將直接格式化的內容傳遞給檢視模板中。由於變數名稱與JSON格式化後的key值相同,會自動將key對應的vlaue代替對應的模板變數,並且將完全代替後的HTML內容顯示在ID號為ulshowstus的<ul>元素中。

    在例項化檢視物件時,指定該檢視物件的模型為stus,進行檢視物件與模型物件間的關聯,並通過呼叫檢視物件的render方法,將檢視模板中代替後的HTML內容顯示在頁面指定ID號的元素中,其最終實現的頁面效果如上圖所示。

6.2.3 顯示多項內容的模板

   在頁面中使用<script>元素新增模板區域之後,預設情況下使用<%= %>標記設定模板變數,但在有些使用服務端程式開發的頁面中,<%= %>標記可能會有衝突或不習慣。針對這種情況,開發人員可以呼叫Underscore框架中的templateSettings函式,使用正規表示式自定義模板變數的標記。接下來通過一個簡單示例進行介紹。

    示例6-6 自定義模板變數標記

1.功能描述

    為了演示修改模板變數標記後的對比效果,將示例6-5程式碼進行修改,呼叫templateSettings函式自定義模板變數標記,其他程式碼功能儲存不變。

<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
<script src="../script/jquery-1.11.1.js"></script>
<script src="../script/underscore.js"></script>
<script src="../script/backbone.js"></script>
<style type="text/css">
	body{
		font-size:13px;
	}
	div{
		width:260px;
		padding:5px;
	}
</style>
</head>
<body>
	<ul id="ulshowstus"></ul>
	<script type="text/template" id="stus-tpl">
		<li>編號:{{Code}}</li>
		<li>姓名:{{Name}}</li>
		<li>分數:{{Score}}</li>
	</script>
</body>
<script type="text/javascript">
	_.templateSettings = {
		interpolate:/\{\{(.+?)\}\}/g
	};
	var student = Backbone.Model.extend({
		defaults:{
			Code:"",
			Name:"",
			Score:0
		}
	});
	var stus = new student({
		Code:"10107",
		Name:"皮卡丘",
		Score:750
	});
	var stuview = Backbone.View.extend({
		el:$("#ulshowstus"),
		initialize:function(){
			this.template = _.template($("#stus-tpl").html())
		},
		render:function(){
			this.$el.html(this.template(this.model.toJSON()));
		}
	});
	var stuv = new stuview({model:stus});
	stuv.render();
</script>
</html>

2.原始碼分析

    在本示例中,為了實現自定義模板變數標記的功能,在示例6-5的基礎之上進行了兩處修改。

    (1)在JavaScript程式碼中,新增了一個名為templateSettings的工具類函式。該函式的功能是設定模板的配置項,其中interpolate屬性為插入變數值匹配項,如果使用正規表示式修改該項的屬性值就可以自定義模板變數的標記,如將該項的屬性值設定為“/\{\{(.+?)\}\}/g”正規表示式,就可以將預設的<%= %>變數標記改為{{ }},也可以根據自己的需求自定義其他的變數標記

    (2)在頁面程式碼中,由於重新設定了模板變數標記,在頁面模板區新增變數時,必須按照新設定的變數標記格式進行變數的新增。

    其餘程式碼的功能在示例6-5中有詳細的介紹,不再贅述。


6.3 檢視中的元素事件

    通過前面章節的學習我們知道,檢視物件與頁面的互動最為密切,檢視類中提供了許多側重於頁面互動的屬性或方法,如el屬性、render方法等。然而,檢視物件與頁面的互動遠沒有這麼簡單。眾所周知,頁面的元素不僅可以顯示內容,還可以通過事件的觸發完成既定的功能,實現人機互動的動態效果。因此,事件也是DOM元素一個重要的特徵。

    在構建檢視類時,可以新增一個events屬性,該屬性的功能是將DOM元素與觸發的事件和執行事件函式相繫結,事件繫結的格式如下。

    eventName element:function

    其中,用冒號:分成前後i兩部分,前面部分定義繫結事件的元素和事件名稱,中間用空格隔開。引數eventName表示繫結事件的名稱,它包含任何DOM都支援的事件,如click、change等;element參數列示獲取繫結元素的選擇器,它支援各類的方式獲取元素,如按類別、ID號、元素標籤獲取。function參數列示事件觸發時執行的處理函式,該函式通常是在檢視內部已定義好的方法。

    檢視的events屬性宣告的是一個DOM元素事件列表,多個元素的繫結事件可以使用逗號隔開,只要在事件列表中進行元素事件的繫結宣告。在例項化檢視物件時,新建立的檢視物件將會自動分析events屬性值中的事件列表。根據element引數獲取DOM元素物件,自動繫結元素事件名稱和事件觸發時執行的函式。接下來通過完整的示例詳細介紹在檢視中元素事件的概念。

6.3.1 檢視中簡單事件繫結

    通過前面的介紹我們知道,在檢視中繫結一個元素的事件非常簡單,只要在events屬性值中按規則宣告就可以。在宣告之前,必須確保事件繫結的頁面元素和事件觸發時執行的處理函式存在即可。接下來通過一個簡單示例進行介紹。

    示例6-7 檢視中簡單事件繫結

1.功能描述

    在頁面瀏覽時,以例項化的方式建立一個檢視物件,呼叫物件的render過載方法向頁面的<body>元素中追加一個<div>元素,並在<div>元素中顯示“backbone是構建前端MVC的利器”字樣,當單擊<div>元素時,自身的樣式也會發生變化。

<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
<script src="../script/jquery-1.11.1.js"></script>
<script src="../script/underscore.js"></script>
<script src="../script/backbone.js"></script>
<style type="text/css">
	body{
		font-size:13px;
	}
	div{
		width:260px;
		padding:5px;
		text-align:center;
	}
	.changed{
		border:solid 1px #555;
	}
</style>
</head>
<body></body>
<script type="text/javascript">
	var stuview = Backbone.View.extend({
		el:$("body"),
		initialize:function(){
			this.render();
		},
		render:function(){
			this.$el.append("<div id='backbone'>backbone是構建前端MVC的利器<div>");
		},
		events:{
			"click div#backbone":"togcls"
		},
		togcls:function(){
			$("#backbone").toggleClass("changed");
		}
	});
	var stuv = new stuview();
</script>	
</html>




2.原始碼分析

    在本示例的JavaScript程式碼中,首先構建檢視類時,通過el屬性繫結頁面中的DOM元素,在構建函式initialize中,呼叫已定義的render方法。該函式在例項化檢視物件時自動執行,因此,當一個檢視物件完成例項化後,在執行initialize函式程式碼時候就已呼叫了render方法。

    為了繫結DOM元素中的事件,在構建檢視類時新增events屬性,在該屬性值中根據檢視事件繫結的規則,宣告ID號為backbone的<div>元素在click事件中執行togcls處理函式。在執行檢視物件的render方法時,將<div>元素追加至<body>元素中,在togcls自定義函式中,便可以按ID號獲取該元素物件,並呼叫物件的toggleClass方法切換自身樣式。

    最後,例項化一個名為stuv的檢視物件,這一操作將觸發建構函式initialize的呼叫,自動執行檢視物件render方法中的程式碼,向<body>元素中新增<div>元素,並自動解析events屬性中宣告的事件列表。通過選擇器獲取DOM元素物件,並將對應的事件繫結到物件中,指定事件觸發時執行的處理函式。其最終實現的頁面效果如上圖所示。



6.3.2 繫結檢視模板中的多個事件

    與繫結頁面中的元素事件相同,在檢視中繫結模板中元素的事件也非常方便。通常情況下,首先呼叫_.template()函式獲取檢視模板中的HTML元素內容,並賦予檢視的template屬性中。檢視物件過載render方法時,將儲存在檢視template屬性中的HTML元素內容以字典傳值的方式新增到el屬性指定的DOM元素中。因此,當檢視物件執行過載render方法後,el屬性指定的DOM元素中已包含模板中的全部HTML元素,這樣就可以像繫結頁面中的元素事件一樣繫結檢視模板中的元素事件。接下來通過一個簡單示例進行介紹。

    示例6-8 繫結檢視模板中的多個事件

1.功能描述

    在頁面中先新增一個<div>元素,用於放模板生成的HTML程式碼。然後使用<script>標記新增一個包含<div>和<input>元素的模板,單擊通過模板生成的<div>元素時,本身會切換顯示樣式,單擊<input>按鈕時,上面的<div>元素會切換顯示狀態。

<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
<script src="../script/jquery-1.11.1.js"></script>
<script src="../script/underscore.js"></script>
<script src="../script/backbone.js"></script>
<style type="text/css">
	body{
		font-size:13px;
	}
	div{
		width:260px;
		padding:5px;
		text-align:center;
	}
	.changed{
		border:solid 1px #555;
	}
</style>
</head>
<body>
	<div id="main"></div>
	<script type="text/template" id="main-tpl">
		<div id="backbone"><%=mess%></div>
		<input id="btnshow" type="button" value="點選一下">
	</script>	
</body>
<script type="text/javascript">
	var stuview = Backbone.View.extend({
		el:$("#main"),
		initialize:function(){
			this.template = _.template($("#main-tpl").html());
			this.render();
		},
		render:function(){
			this.$el.html(this.template({
				mess:"backbone是構建前端MVC的利器"
			}));
		},
		events:{
			"click div#backbone":"togcls",
			"click input#btnshow":"toggle"
		},
		togcls:function(){
			$("#backbone").toggleClass("changed");
		},
		toggle:function(){
			$("#backbone").toggle();
		}
	});
	var stuv = new stuview();
</script>
</html>



2.原始碼分析

    在本示例的頁面中,首先定義一個ID號為“main”的<div>元素,還使用<script>標記定義一個ID號為“main-tpl”的檢視模板,在模板中定義一個名為“mess”的模板變數,用於接收並顯示傳入的內容。

    在頁面的JavaScript程式碼中,通過檢視類的建構函式initialize將模板中的HTML元素內容儲存到檢視template屬性中,並在過載render方法時,將這些已儲存的模板HTML元素內容新增到ID號為“main”的頁面元素中,實現在頁面中生成模板元素和內容的過程。

    在構建檢視類時,為了繫結模板中的元素事件,新增了events事件屬性。在該屬性值中,按照繫結元素事件的規則,以逗號間隔。宣告ID號為“backbone”和“btnshow”兩個元素所繫結的事件和事件觸發時執行的函式。第一個元素繫結的事件名為“click”,觸發時執行togcls處理函式,該處理函式通過呼叫toggleClass方法實現樣式的切換顯示;第二個元素繫結的事件名也為“click”,觸發時執行toggle處理函式,該處理函式通過呼叫toggle方法實現顯示狀態的切換。

    在本示例的JavaScript程式碼最後一行,例項化一個名為“stuv”的檢視物件,在例項化的過程中,將自動觸發檢視的重構函式的呼叫,過載檢視物件的render方法,實現在頁面中生成模板元素和內容及自動繫結已宣告元素事件的過程,其最終實現的頁面效果如上圖所示。


6.3.2 動態繫結和取消檢視中的事件

    除了在構建檢視類中,通過events屬性的方式宣告繫結元素的事件之外,檢視內部還提供了delegateEvents和undelegateEvents兩個方法,用於動態繫結和取消繫結元素的事件。

    delegateEvents方法的功能是重新繫結events屬性值中已宣告的全部元素事件,其呼叫格式如下程式碼所示。

    delegateEvents([events])

    其中,可選項引數events為檢視物件的events屬性值,也可以不新增該引數,預設值就是檢視物件自身的events屬性值。

    undelegateEvents方法的功能是取消所有已繫結元素的事件,其呼叫格式如下所示。

    undelegateEvents()

    該方法無引數,直接呼叫即可。接下來通過一個簡單示例進行介紹。

    示例6-9 動態繫結和取消檢視中的事件

1.功能描述

    在頁面中,首先新增一個<div>元素,用於接收並生成模板中的元素內容。然後使用<script>標記新增一個檢視模板,在模板按中新增一個用於顯示文字內容的<div>元素和三個功能按鈕。

    單機“切換樣式”按鈕時,可以切換模板中<div>元素的樣式;單擊“取消繫結”按鈕後,“切換樣式”按鈕的功能將失效;單擊“重新繫結”按鈕之後,“切換樣式”按鈕的功能又重新恢復。

<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
<script src="../script/jquery-1.11.1.js"></script>
<script src="../script/underscore.js"></script>
<script src="../script/backbone.js"></script>
<style type="text/css">
	body{
		font-size:13px;
	}
	div{
		width:260px;
		padding:5px;
		text-align:center;
	}
	.changed{
		border:solid 1px #555;
	}
</style>
</head>
<body>
	<div id="main"></div>
	<script type="text/template" id="main-tpl">
		<div id="backbone">backbone是構建前端MVC的利器</div>
		<input type="button" id="btn_a" value="切換樣式"/>
		<input type="button" id="btn_b" value="取消繫結"/>
		<input type="button" id="btn_c" value="重新繫結" onclick="stuv.rebind()"/>
	</script>
</body>
<script type="text/javascript">
	var stuv = null;
	var stuview = Backbone.View.extend({
		el:$("#main"),
		initialize:function(){
			this.template = _.template($("#main-tpl").html());
			this.render();
		},
		render:function(){
			this.$el.html(this.template());
		},
		rebind:function(){
			this.delegateEvents(this.events);
		},
		events:{
			"click input#btn_a":"btnclick_a",
			"click input#btn_b":"btnclick_b"
		},
		btnclick_a:function(){
			$("#backbone").toggleClass("changed");
		},
		btnclick_b:function(){
			this.undelegateEvents();
		}
	});
	stuv = new stuview();
</script>
</html>


2.原始碼分析

   在本示例的頁面程式碼中,首先新增一個ID號為“main”的<div>元素,用於顯示檢視模板元素的內容,並使用<script>標籤在頁面中新增ID號為“main-tpl”的模板。

    在JavaScript程式碼中,先定義一個全域性變數stuv,用於儲存例項化後的檢視物件。接下來,在stuview的檢視中的initialize建構函式中獲取頁面中的模板物件,並在檢視物件過載render方法時,將模板中的HTML元素內容生成到el屬性指定的元素中,實現在頁面中生成模板元素和內容的過程。

    在檢視的events屬性宣告各個DOM元素所繫結的事件中,“切換樣式”和“取消繫結”按鈕繫結的click事件對應執行的處理函式為“btnclick_a”和“btnclick_b”,前者呼叫toggleClass方法實現元素樣式顯示的切換功能,後者呼叫undelegateEvents方法實現取消檢視物件中全部元素已繫結事件的功能。

    由於執行undelegateEvents方法之後,該檢視中所有通過events屬性值宣告的繫結事件都被取消,因此“重新繫結”按鈕所執行的click事件直接在定義元素時進行新增,這樣在執行undelegateEvents方法後是不會取消“重新繫結”這個點選事件的。該事件執行的處理函式為stuv.rebind(),stuv是例項化後的檢視物件名稱。rebind是一個自定義的方法,功能是呼叫delegateEvents方法重新繫結檢視物件的events屬性值中全部宣告的元素事件。因此,單擊“重新繫結”按鈕之後,“切換樣式”按鈕事件被重新繫結,功能使用恢復正常。

    本示例的JavaScript程式碼的最後一行,使用new關鍵字例項化一個檢視物件,並將該物件賦予全域性變數stuv,在檢視例項化過程中執行的操作與示例6-8基本相同,不再贅述。


6.4 使用Backbone框架開發前端Web應用

    通過前面的學習,我們對Backbone框架的各個主要功能類模組有了一定的瞭解。總體來講,Backbone框架中的model物件表示資料模型,用於定義資料結構;collcetion物件是管理資料模型的集合,用於儲存或查詢資料;view物件的主要功能是資料顯示,並用於繫結DOM元素事件和處理頁面邏輯。接下來通過一個完整的示例,詳細介紹利用Backbone框架開發一個單頁前端Web應用的過程。

6.4.1 功能描述

    應用包括兩個功能。首先資料錄入功能,在頁面中增加3個文字輸入框分別用於輸入“編號”、“姓名”、“分數”;增加一個“提交”按鈕,單擊該按鈕時,將輸入的資料以模型物件的方式新增到集合物件中。其次是資料顯示功能,當輸入的資料新增完成之後,將已新增的資料通過檢視物件展現在頁面的指定元素中。

<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
<script src="../script/jquery-1.11.1.js"></script>
<script src="../script/underscore.js"></script>
<script src="../script/backbone.js"></script>
<style type="text/css">
	body
        {
            font-size: 12px;
        }
        ul
        {
            list-style-type: none;
            padding: 0px;
            margin: 0px;
            width: 270px;
        }
        ul li
        {
            margin: 5px 0px;
        }
        ul .lh
        {
            font-weight: bold;
            border-bottom: solid 1px #555;
            background-color: #eee;
            height: 23px;
            line-height: 23px;
        }
        ul .lc
        {
            border-bottom: dashed 1px #ccc;
            height: 23px;
            line-height: 23px;
        }
        ul li span
        {
            padding-left: 10px;
            width: 80px;
            float: left;
        }
</style>
</head>
<body>
	<ul id="ulshowstus">
		<li class="lh">
			<span>編號</span>
			<span>姓名</span>
			<span>分數</span>
		</li>
	</ul>
	<br/>
	<ul>
		<li>
			編號
			<input type="text" id="txtCode">
		</li>
		<li>
			姓名
			<input type="text" id="txtName">
		</li>
		<li>
			分數
			<input type="text" id="txtScore">
		</li>
		<li>
			<input id="btnSubmit" type="button" value="提交"/>
		</li>
	</ul>
	<!-- 模板程式碼 -->
	<script type="text/template" id="stus-tpl">
		<li class="lc">
			<span><%=Code%></span>
			<span><%=Name%></span>
			<span><%=Score%></span>
		</li>
	</script>
</body>
<script type="text/javascript">
	var student = Backbone.Model.extend({
		defaults:{
			Code:"10001",
			Name:"張三",
			Score:100
		}
	});
	var stulist = Backbone.Collection.extend({
		initialize:function(model,options){
			this.on("add",options.view.showmodel);
		}
	});
	var stuview = Backbone.View.extend({
		el:$("body"),
		initialize:function(){
			this.stul = new stulist(null,{view:this})
		},
		events:{
			"click #btnSubmit":"addmodel"
		},
		addmodel:function(){
			var stum = new student({
				Code:$("#txtCode").val(),
				Name:$("#txtName").val(),
				Score:$("#txtScore").val()
			});
			this.stul.add(stum);
		},
		showmodel:function(model){
			this.template = _.template($("#stus-tpl").html());
			$("#ulshowstus").append(this.template(model.toJSON()));
		}
	});
	var stuv = new stuview();
</script>
</html>

2.原始碼分析

    本示例的原始碼由頁面程式碼和JavaScript程式碼兩部分組成。通常情況下,頁面程式碼是為了配合JavaScript程式碼的功能開發而設定的。本示例的頁面程式碼由三部分組成,分別包含兩個<ul>元素和一個<script>模板元素。ID號為“ulshowstus”的<ul>元素用於生成並顯示<script>模板元素生成的HTML內容。在另一個<ul>元素中,新增三個<input>文字輸入框和一個按鈕元素,用於錄入模型物件的各屬性值和整個資料的提交。

    在本示例的JavaScript程式碼中,由自定義的模型類、集合類、檢視類三個部分組成,在構建student模型類時,使用defaults屬性定義模型物件的基本屬性結構並設定了初始值。在構建stulist集合類時,在建構函式iniaitlize中繫結物件的add事件,向集合中新增模型物件時將觸發該事件,並執行形參options中view物件的showmodel方法。

    在構建stuview檢視類時,首先將el屬性值設定為<body>元素,還在建構函式initialize中以例項化的方式定義一個stul集合物件。在定義過程中,採用字典的方式將view的實參值設為this,即例項化檢視物件本身;而在集合物件例項化時,也同時觸發了stulist集合類中的建構函式的呼叫。在呼叫過程中,形參options中view物件將自動變為傳來的檢視物件,因此向集合物件中新增模型物件時,將執行檢視物件中的showmodel方法。

    為了繫結ID號為“btnSubmit”的“提交”按鈕的click事件,在構建stuview集合類時,新增了events屬性。在屬性值中定義了按鈕的click事件,當觸發該按鈕的click事件時,將執行addmodel函式。在該處理函式中,先例項化一個stum模型物件,頁面中三個文字框輸入的值作為例項化物件時的實參值新增到模型物件中,然後呼叫add方法向向已定義的集合物件stul新增該模型物件。由於在呼叫add方法時,觸發了已繫結的對應事件,在該事件處理函式中,將呼叫檢視物件內部的showmodel方法,完成新增加模型物件的資料顯示功能。

    在檢視內部自定義的showmodel方法中,先將頁面中的模板賦予檢視本身的template屬性值,並將傳回的model物件內容轉成JSON格式再次過載template屬性,最後將模板過載後的結果追加至ID號為“ulshowstus”的元素中,從而實現顯示新增加模型物件資料的功能。


相關文章