Backbine.js實戰第四章----資料模型

我叫阿狸貓發表於2014-10-31

    Model在Backbone中為資料模型,是一個最基礎、最基本的資料基類,用於原始資料、底層方法的封裝和定義。它的結構類似於關聯式資料庫中的對映物件,可以裝在資料庫中的記錄資訊,並通過自定義的方法完成資料的操作之後,將資料同步到伺服器中。正確理解和掌握Model的概念和使用方法,是熟悉使用Backbone框架開發的一項重要標誌。


4.1 建立資料模型

   在Backbone中,建立資料模型的方法十分簡單,只要通過Model.extend()方法就可以定義一個資料模型。在定義模型的過程中,還可以初始化資料、定義構造方法,當一個資料模型建立完成後,可以通過例項化的方式,產生一個個資料模型物件。 這些模型物件都繼承了資料模型中的初始化資料,並且可以很方便地呼叫建立時設定的方法。接下來逐一進行介紹。


4.1.1 建立一個簡單模型物件

    當使用Model.extend()方法構建資料模型之後,就可以通過例項化的方式建立一個模型物件,模型物件將自動繼承模型中定義的屬性和方法。

    示例4-1  建立一個簡單模型物件

 1.功能描述

    在構建模型物件時,首先新增initialize函式,在該函式中,通過一個名為"intNum"的變數累計執行函式的次數,並將該次數顯示在瀏覽器的控制檯中。然後,例項化兩個模型物件,在例項化過程中,將自動執行initialize函式,觀察瀏覽器控制檯輸出內容的變化。

var student = Backbone.Model.extend({
	initialize:function(){
		intNum++;
		console.log("您構建了"+intNum+"個物件");
	}
});
var intNum = 0;
var stuA = new student();
var stuB = new student();


   在上述程式碼中,使用extend方法構建了一個資料模型student,通過initialize屬性定義了一個當資料模型被例項化時執行的函式,即建構函式,它的功能是通過變數intNum記錄建構函式執行的次數,並將結果輸出到瀏覽器的控制檯中。接下來,定義並初始化變數intNum,並以例項化的方式定義兩個模型物件,分別為stuA和stuB。從上圖中可以看出,每當例項化一個模型物件時,都會呼叫建構函式,因此記錄建構函式執行次數變數intNum將會自動累加。本例項中兩次例項化模型物件,因此執行了兩次建構函式。


4.1.2 物件模型賦值的方法

    對於一個資料模型來說,賦值的方法是在定義時通過defaults屬性設定資料模型的預設值,而對於一個已經例項化的模型物件來說,賦值的方法是通過呼叫物件的set方法,重置模型中的預設值。set方法有兩種形式。

    第一種是單個設定,程式碼如下所示。

Obj.set(attrName,attrValue);

    其中,引數attrName表示屬性名稱,attrValue表示對應的屬性值。呼叫上述方式一次只能設定一個屬性值。

    第二種形式為批量設定屬性值,程式碼如下所示。

Obj.set({attrName1:attrValue1,attrName2:attrValue2,...});

    其中,通過{...}方式可以設定多個屬性值,屬性名稱與對應值之間使用冒號(:)隔開,而屬性與屬性之間,則使用逗號(,)隔開。

    無論使用set方法的何種形式賦值,當完成物件賦值操作之後,就可以通過呼叫物件的get或escape方法獲取已設定的物件屬性值,其呼叫格式如下。

Obj.get(attrName);

Obj.escape(attrName);

    其中,引數attrName表示需要獲取的屬性名稱,而get與escape方法雖然都可以獲取物件的屬性值。但兩者間的區別在於escape方法不僅獲取物件的屬性值,而且能將屬性值中包含HTML程式碼的部分進行實體化,即變成一個統一的字串實體,這樣可以有效避免程式碼被攻擊,確保取值的安全。接下來通過一個簡單的示例來演示物件賦值和取值的過程。


    示例4-2  物件模型賦值的方法

1.功能描述

    在構建模型類時,首先新增defaults屬性設定模型物件的屬性名稱,然後例項化一個名為“stuA”的模型物件,並呼叫物件的set方法重置屬性值,最後在瀏覽器的控制檯中輸出這些重置後的屬性值內容。

var student = Backbone.Model.extend({
	initialize:function(){
		//執行構造程式碼
	},
	defaults:{
		Code:"",
		Name:"",
		Score:""
	}
});
var stuA = new student();
stuA.set({
	code:"10101",
	Name:"'皮卡丘'",
	Score:"300",
	Class:"一年級<二>班"
});
console.log(stuA.get("Name")+"在"+stuA.get("Class")+"讀小學");
console.log(stuA.escape("Name")+"在"+stuA.escape("Class")+"讀小學");


2.原始碼分析

    在上述程式碼中,當構建student資料模型時,通過defaults屬性設定了模型的3個預設屬性,並將它們的屬性值設為空,以方便例項化物件時重置屬性值。當例項化一個模型物件stuA之後,通過呼叫物件的set方法,重置模型中3個預設屬性值,並新增一個Class屬性,同時設定屬性值。最後在瀏覽器的控制檯中呼叫物件的get和escape兩種方法輸出物件的指定屬性值。

    從上圖中可以看出,在構建物件模型時,不僅可以通過defaults屬性設定預設屬性並賦值,還可以呼叫物件的set方法賦值的時候自定義屬性,如本例的Class屬性;另外,使用get和escape方法獲取屬性值時,前者原樣獲取,後者會將屬性值中包含的HTML特殊字元進行編碼處理後再返回,如將示例中的單引號處理成“&#x27”等。


4.1.3 自定義模型中的方法

    在構建物件模型時,不僅可以設定模型物件的預設屬性,而且還可以自定義模型物件的方法。眾所周知,與設定屬性相比,自定義模型物件的方法通常需要實現一些相應的功能,在方法中可以使用this物件訪問模型物件本身。

    示例4-3  自定義PrintLog方法

1.功能描述

    在示例4-2程式碼的基礎上,自定義一個名稱為PrintLog的方法,然後例項化一個模型物件之後。通過物件呼叫該方法,在瀏覽器的控制檯輸出物件重置後的屬性內容。

var student = Backbone.Model.extend({
	initialize:function(){
		
	},
	defaults:{
		
	},
	PrintLog:function(){
		console.log(this.get("Name")+"在"+this.get("Class")+"讀小學");
		console.log(this.escape("Name")+"在"+this.escape("Class")+"讀小學");
	}
});
var stuA = new student();
stuA.set({
	Code:"10102",
	Name:"皮卡丘",
	Score:"300",
	Class:"一年級<一>班"
});
stuA.PrintLog();


2.原始碼分析

    在上述程式碼中,當構建資料模型student時,以函式的方式自定義一個名為PrintLog的方法,該方法的功能是在瀏覽器的控制檯中輸出樹勇get和escape方法獲取的物件屬性值。當例項化一個模型物件stuA,並使用set方法新增並重置物件屬性之後,就可以像呼叫物件自帶方法一樣,呼叫自定義的PrintLog方法。

    從圖中可以看出,採用呼叫物件的方式實現的效果與執行輸出程式碼是完全一樣的,但呼叫物件方法的形式使程式碼更簡潔、通用性好、可維護性更加。另外,需要說明的是,在自定義方法時,程式碼this.get("Name")中的this表示物件本身,當沒有重置物件的屬性值,它將獲取構建模型時設定的預設屬性值,否則獲取重置後的物件屬性值。


4.1.4 監聽物件屬性變化

    在第3章介紹事件API時,演示過呼叫on方法繫結物件的屬性事件,其實也可以在構建資料模型時,使用on方法去繫結物件的屬性事件,監聽屬性值的變化而繫結的過程程式碼,通常放在資料模型建構函式initialize中,這樣,當例項化某個資料模型物件時,就自動繫結了物件的事件,一旦觸發了事件,便可以執行相應的程式碼。

    示例4-4  監聽Name屬性值的變化

1.功能描述

    在示例4-3的基礎上,向資料模型建構函式initialize中繫結物件的一個屬性事件,監聽Name屬性值的變化。

var student = Backbone.Model.extend({
	initialize:function(){
		this.on("change:Name",function(){//這裡可以不寫model,value引數
			var oldName = this.previous("Name");
			var newName = this.get("Name");
			if(oldName!=newName){
				console.log("Name原值:"+oldName+",新值:"+newName);
			}
		});
	},
	defaults:{
		Code:"",
		Name:"皮卡丘",
		Score:""	
	}
});
var stuA = new student();
stuA.set("Name","傑尼龜");

2.原始碼分析

    在上述程式碼中,當構建資料模型時新增了建構函式initialize,在這個函式中使用on方法繫結物件屬性事件change:Name。在該事件執行的自定義函式中,分別用oldName和newName兩個變數儲存上一次和修改後的Name屬性值,如果這兩個值發生變化,在瀏覽器的控制檯中輸出Name屬性的原值和新值內容。

    接下來,例項化一個模型資料物件stuA,並呼叫該物件的set方法重置了Name屬性值,這一操作將觸發已繫結的change:Name屬性事件,並執行事件的自定義函式。

    從上圖中可以看出,在建構函式中,同樣可以呼叫物件的on方法繫結各類事件,監聽事件的觸發。由於在本示例中,物件的Name屬性預設值為“皮卡丘”,而呼叫set方法重置為“傑尼龜”。當觸發change:Name事件時,Name屬性值已經發生了變化,所以在瀏覽器控制檯輸出獲取的Name屬性的原值和新值。

    需要說明的是,建構函式this.on中的this表示例項化後的物件本身,而this.previous中的this雖然也表示物件本身,但如果建構函式中帶有model和value兩個屬性事件特有的引數,則 this可以被取代,即下面兩行程式碼是等價的。

    var oldName = this.previous("Name");

    var newName = this.get("Name");

等價於:

    var oldName = model.previous("Name");

    var newName = value;


4.2 模型物件操作

     構建一個資料模型類之後,接下來的任務就是針對模型例項化物件,並對例項化後的物件進行一系列的資料操作,如讀取、(重置)修改、驗證、刪除物件中資料。接下來逐一介紹這些操作實現的方法和技巧。

4.2.1 讀取資料

    前面章節介紹過,如果要讀取一個模型物件中的資料,通常呼叫物件的get和escape方法,前者是直接返回物件中的資料,後者則是返回經過物件中某些特殊字元進行編碼處理後的資料。接下來分別對這兩種方法進行介紹。

    示例4-5  呼叫get方法獲取物件指定的屬性值

1.功能描述

    首先構建一個模型類,設定預設的屬性名稱,然後例項化一個名為“stuA”的模型物件,最後在瀏覽器的控制檯中輸出使用get方法獲取的物件屬性值。

var student = Backbone.Model.extend({
	defaults:{
		Code:"",
		Name:"",
		Score:""	
	}
});
var stuA = new student({
	Code:"10103",
	Name:"皮卡丘",
	Socre:""
});
console.log("學號:"+stuA.get("Code"));
console.log("姓名:"+stuA.get("Name"));
console.log("性別:"+stuA.get("Sex"));
console.log("分數:"+stuA.get("Score"));

2.原始碼分析

    在上述程式碼中,首先構建了一個資料模型student,在該模型中,通過defaults屬性設定物件的一些預設屬性值。然後,例項化一個模型物件stuA,在例項化過程中,重置物件的3個屬性值。最後呼叫get方法獲取物件指定的屬性值,並將這些值輸出在瀏覽器的控制檯中。

    從上圖中可以看出,當使用物件的get方法讀取資料時,會自動與上一次的值進行比較。如果沒有發生變化,返回上一次的物件資料;否則,獲取變化後最新的物件資料。如果不存在該項資料名稱,則返回undefined值。


4.2.2 修改資料

     完成一個資料模型的構建之後,就可以通過例項化的物件修改模型類中的預設屬性值。常用方法有兩種:一種是在例項化物件的同時修改預設的屬性值,另一種是呼叫物件的set方法針對一個或多個屬性進行重置。當資料修改後,如果不與上一次的值相同,可以呼叫物件的get或escape方法進行獲取。

    示例4-6 呼叫set方法批量重置預設屬性值

1.功能描述

    首先構建一個模型類,並設定預設的屬性名稱。然後,分別例項化stuA和stuB兩個模型物件。在例項化過程中,物件stuA在例項化時,直接給預設的屬性名賦值,而物件stuB則通過set方法,在物件例項化後批量賦值。最後,在瀏覽器控制檯中輸出兩個物件的屬性值。

var student = Backbone.Model.extend({
	defaults:{
		Code:"",
		Name:"",
		Score:""	
	}
});
var stuA = new student({
	Code:"10104",
	Name:"皮卡丘",
	Score:"500"
});
var stuB = new student();
stuB.set({
	Code:"10105",
	Name:"傑尼龜",
	Score:"300"
});
console.log("1.學號:"+stuA.get("Code")+
			"  姓名:"+stuA.get("Name")+
			"  分數:"+stuA.get("Score"));
console.log("2.學號:"+stuB.get("Code")+
			"  姓名:"+stuB.get("Name")+
			"  分數:"+stuB.get("Score"));

2.原始碼分析

    在上述程式碼中,分別例項化兩個模型物件stuA和stuB。前者是在例項化時便修改了物件模型的預設屬性值,後者則是在例項化物件之後,使用set方法批量重置物件模型中的預設屬性值。最後呼叫物件的get方法獲取物件資料,並輸出至瀏覽器的控制檯中。

    從上圖中可以看出,無論是使用例項化物件的同時修改屬性值,還是例項化之後使用set方法重置物件的屬性值,都可以呼叫get方法獲取。


4.2.3 開啟資料驗證

    Backbone中提供了一套完整的資料驗證機制,用於確保寫入資料模型中資料的正確性,尤其是在最新的1.0.0版本,改變了之前的自動驗證方式,改為設定驗證方式。接下來詳細介紹Backbone .1.0.0中,資料驗證實現的方法。

    要實現對資料中某個屬性值的驗證,需要完成一下3個步驟的操作。

    (1)新增validate方法。在該方法中確定資料校驗的標準,即資料在什麼情況下,認為它是不正確的,如果不正確,返回提示資訊。

    (2)繫結物件validate事件。 資料驗證失敗後會觸發該事件,在該事件中,通過返回的引數可以接收validate方法中傳來的提示資訊。

    (3)使用set方法新增/修改屬性時,必須將validate屬性設定為true,用於通知Backbone框架此次的資料操作是需要進行驗證的。

    通過上述步驟的操作,就可以開啟對某項資料的驗證,下面通過一個簡單的示例來說明資料驗證的過程。

    示例4-7 開啟資料驗證

1.功能描述

    在構建模型類時,首先新增validate方法,在該方法中對屬性中的“姓名”和“分數”做有效性驗證。然後,通過set方法重置屬性值,並將validate的值設為true。更新一個不符合驗證規則的屬性值時,在瀏覽器的控制檯中以JSON形式輸出原有物件屬性值內容。

var student = Backbone.Model.extend({
	initialize:function(){
		this.on("invalid",function(model,error){
			console.log(error);
		});
	},
	validate:function(attrs){
		if(!_.isString(attrs.Name)){
			return "姓名必須是字元!";
		}
		if(!_.isNumber(attrs.Score)){
			return "分數必須是數字!";
		}
	},
	defaults:{
		Code:"10001",
		Name:"張三",
		Score:100
	}
});
var stuE = new student();
stuE.set({
	Code:"10105",
	Name:12345,
	Score:600
},{"validate":true});
console.log(stuE.toJSON());

2.原始碼分析

    在上述程式碼中,構建資料模型類,在建構函式中繫結物件的inalid事件。在該事件中,將在瀏覽器的控制檯輸出驗證錯誤提示資訊。其次,在資料模型類中,新增validate方法,設定了Name、Score兩個屬性的驗證規則。最後,在呼叫例項化物件stuE的set方法時,將validate屬性值設定為true。

    由於在呼叫例項化物件stuE的set方法時,將Name屬性的值重置為12345,這是一個數字型別,這樣的設定不符合“Name屬性必須為字元”的規則。由於開啟了驗證,將呼叫validate方法的規則進行對應資料的驗證。驗證失敗後,觸發已繫結invalid事件,接收傳回的錯誤提示資訊,並將該資訊輸出至瀏覽器的控制檯中。

    另外,在呼叫validate方法進行資料驗證時,將會逐一對規則進行過濾。如果驗證失敗,會終止整個set方法的操作,直接執行invalid事件中的程式碼。也就是說,本示例中由於Name屬性沒有通過驗證,即使Score屬性設定了正確的值,也不會進行更新。因為整個操作都已停止,通過最後一行程式碼輸出物件stuE的全部資料可以看出,stuE物件中的各屬性值仍然是初始化的值,沒有發生變化。

    
4.2.4 關閉資料驗證

    在Backbone中呼叫set方法時,不將validate屬性值設定為true,本次set方法將不會進行資料驗證。此外,在呼叫set方法時,還可以將silent屬性值設定為true,表示靜默式修改資料,即在修改資料時,不觸發任何事件。這其中也包括繫結的屬性事件,當然也不會觸發資料驗證事件,而是直接更新資料。

    示例4-8 關閉資料驗證

1.功能描述

    在示例4-7基礎之上進行修改,只在使用set方法重置屬性值時,將silent屬性值設定為true,不設定validate,其餘程式碼不變。最後,將重置後的物件屬性值內容以JSON格式的形式輸出至瀏覽器的控制檯中。

var student = Backbone.Model.extend({
	initialize:function(){
		this.on("invalid",function(model,error){
			console.log(error);
		});
		this.on("chaneg:Name",function(model,value){
			console.log("您觸發了Name屬性修改事件!");
		});
	},
	validate:function(attrs){
		if(!_.isString(attrs.Name)){
			return "姓名必須是字元!";
		}
		if(!_.isNumber(attrs.Score)){
			return "分數必須是數字!";
		}
	},
	defaults:{
		Code:"10001",
		Name:"張三",
		Score:100
	}
});
var stuE = new student();
stuE.set({
	Code:"10105",
	Name:12345,
	Score:600
},{"silent":true});
console.log(stuE.toJSON());
2.原始碼分析

    上述程式碼在示例4-7基礎新增了一個物件的change:Name事件。在呼叫物件set方法時,將Name和Score的屬性值分別設定為數字和字元型別,以觸發驗證的事件,同時將silent屬性值設定true。最後,在瀏覽器的控制檯中輸出整個stuE物件的屬性值。

   由於在set方法中將silent屬性值設定true,表示將關閉所有觸發的事件,採用靜默方式進行更新,因此,即使設定的屬性值不符合驗證規則,validate方法也不會被觸發,而是直接重置物件的屬性值。在屬性值被重置的過程中,雖然已繫結change:Name事件,但由於是靜默方式更新,該事件同樣也不會被觸發。最終在瀏覽器的控制檯中輸出更新後的資料。

4.2.5 更新資料回滾

    在Backbone中呼叫set方法時,可以將silent屬性值設定為true,採用靜默方式更新資料。但為了確保資料的安全性,可以針對已更新的資料進行二次驗證,如果不符合驗證規則,可以呼叫物件的previous方法進行上一次資料的回滾。

    示例4-9 更新資料回滾

1.功能描述

    在示例4-8基礎之上進行修改,關閉資料驗證後,對已經重置的物件屬性值進行手動驗證,以確定其資料的有效性。如果手動驗證不成功,將用previouse方法獲取的資料回滾值重置為物件的屬性值。最後,在瀏覽器的控制檯以JSON形式輸出物件的屬性內容。

var student = Backbone.Model.extend({
	initialize:function(){
		this.on("invalid",function(model,error){
			console.log(error);
		});
		this.on("chaneg:Name",function(model,value){
			console.log("您觸發了Name屬性修改事件!");
		});
	},
	validate:function(attrs){
		if(!_.isString(attrs.Name)){
			return "姓名必須是字元!";
		}
		if(!_.isNumber(attrs.Score)){
			return "分數必須是數字!";
		}
	},
	defaults:{
		Code:"10001",
		Name:"張三",
		Score:100
	}
});
var stuE = new student();
stuE.set({
	Code:"10105",
	Name:12345,
	Score:600
},{"silent":true});
console.log(stuE.toJSON());
if(!_.isString(stuE.get("Name"))||!_.isNumber(stuE.get("Score"))){
	stuE.set({
		"Name":stuE.previous("Name"),
		"Score":stuE.previous("Score")
	});
}
console.log(stuE.toJSON());

2.原始碼分析

    在上述程式碼中,呼叫物件stuE的get方法獲取屬性當前最新的值,然後進行二次驗證。如果沒有通過驗證,再次呼叫物件set方法,將使用previous方法獲取的上一次資料更新為物件的最新值,實現物件資料的回滾。

    雖然在第一次呼叫set方法時啟用靜默方式,更新兩個不符合驗證規則的屬性值,但通過資料的二次驗證,呼叫previous方法獲取第一次set方法更新之前的資料,並再次呼叫set方法將獲取的資料進行更新,實現異常資料的回滾。

    上圖中雖然都是輸出物件stuE的JSON格式值,但兩次輸出的內容卻不同,第一次輸出的是採用靜默方式更新後的值,第二次輸出的是資料回滾之後物件stuE的屬性值。


4.2.6 刪除資料

    在Backbone中,可以呼叫物件的unset和clear方法刪除模型物件中的資料,前者是刪除指定屬性名稱的資料,呼叫格式如下。

Obj.unset(attrName);

    後者為清除物件中的全部資料,該方法沒有引數,呼叫的格式如下。

Obj.clear();

    接下來通過簡單的示例介紹使用unset和clear方法刪除模型中物件資料的過程。

    示例4-10 呼叫unset方法刪除指定屬性的資料

1.功能描述

    首先構建一個模型類,例項化一個名為“strE”的類物件。然後,呼叫set方法重置物件的屬性值。最後,分別呼叫unset和clear方法刪除指定的某個和全部的屬性資料,在刪除過程中,分別在瀏覽器的控制檯中輸出資料刪除後的物件屬性值。

var student = Backbone.Model.extend({
	initialize:function(){
		//建構函式
	},
	defaults:{
		Code:"10001",
		Name:"張三",
		Score:100
	}
});
var stuE = new student();
stuE.set({
	Code:"10106",
	Name:"皮卡丘",
	Score:650
});
//刪除name屬性
stuE.unset("Name");
console.log(stuE.get("Name"));
console.log(stuE.toJSON());
stuE.set("Name",stuE.previous("Name"));
console.log(stuE.toJSON());
//清除全部資料
stuE.clear();
console.log(stuE.toJSON());


2.原始碼分析

    在上述程式碼中,首先呼叫stuE物件的set方法更新一次資料,同時呼叫物件的unset方法刪除Name屬性的資料,並輸出刪除資料後,Name屬性值和整個stuE物件的JSON格式內容。然後第二次呼叫set方法,將Name屬性回滾後的值更新為當前最新屬性值,並再次輸出整個stuE物件的JSON格式內容。最後,呼叫物件的clear方法清空stuE物件的全部資料,並再次以JSON格式輸出物件的內容。

    當刪除stuE物件的Name屬性資料之後,再次呼叫該屬性值時,將返回undefined,表示對應屬性已經不存在;同時,以JSON格式輸出整個stuE物件時,Name屬性同樣不存在。通過這點可以看出,使用unset方法不僅是刪除屬性的資料,而且該屬性也一併刪除,這是因為當模型物件執行unset方法時,模型內部將呼叫delete關鍵字將Name屬性從物件中移除,從而實現刪除資料的功能。

    由於unset方法也是資料更新方法的一種,也能呼叫previous方法對已刪除的資料進行回滾。因此,在本示例中,當呼叫previous方法獲取回滾後的Name屬性值,並將該值使用set方法重置為Name屬性的新值後,再次以JSON格式輸出整個stuE物件時,已刪除的資料又重新返回,如上圖中第三行所示。

    呼叫stuE物件的clear方法清空整個物件的資料之後,全部的資料都將被刪除,包括物件的屬性和屬性值。因此,最後一次以JSON格式輸出整個stuE物件時,該物件的內容是一個空值,如上圖中第四行所示。



4.3 物件屬性操作

    在Backbone中,每一個例項化後的模型物件都包含一個或多個屬性,可以通過呼叫物件的set方法設定這些屬性的值,並呼叫物件的get方法返回指定屬性名稱的值。使用者對模型物件的資料操作,在本質上來說,就是對一個個物件屬性的操作。本章將進一步介紹操作物件屬性的原理和獲取屬性修改前資料的方法。

4.3.1 attributes物件

    在Backbone中,例項化後的模型物件所有屬性都儲存在一個名為attributes的物件中,物件的set或get方法都是圍繞該物件進行存取的。使用set方法設定物件屬性值時,該方法內部執行了一個相容。即第一個引數ket是物件時,直接將該物件複製到attributes中;如果是字串形式,則在內部將key和value轉成一個臨時的物件attrs,再把它賦值到attributes中,這樣可以使set方法支援單個屬性值和多個屬性值的設定。

    除使用get方法獲取物件指定的屬性值外,還可以直接呼叫物件attribute的方法獲取全部的屬性值。獲取的方式有兩種:一種是直接輸出attributes物件,另一種是遍歷attributes物件,獲取並輸出物件中的屬性值。

    示例4-11 呼叫attributes物件獲取全部的屬性值

1.功能描述

    在構建並例項化一個模型物件後,首先在瀏覽器的控制檯中輸出該物件的整個attributes內容,然後以遍歷的方式在瀏覽器的控制檯中分別輸出attributes中的每一項值。

var student = Backbone.Model.extend({
	initialize:function(){
		//建構函式
	},
	defaults:{
		Code:"10001",
		Name:"張三",
		Score:100
	}
});
var stuE = new student();
stuE.set({
	Code:"10106",
	Name:"皮卡丘",
	Score:650
});
//直接輸出attributes物件
console.log(stuE.attributes);
//遍歷後輸出attributes物件中的每項屬性和值
var attrs = stuE.attributes;
for(var i in attrs){
	console.log(i+":"+stuE.attributes[i]);
}

2.原始碼分析

    從上圖中可以看出,直接輸出attributes物件時,它是以JSON格式的形式形式顯示的,因此下列兩端程式碼是等價的。

console.log(stuE.attributes);

等價於:

console.log(stuE.toJSON());

    以遍歷的方式也可以獲取attributes物件中的某項屬性值,如上圖中2、3、4行所示。因此,可以針對某項屬性值進行修改。


注意:

    雖然這種方式也可以獲取物件的屬性值,但這種方法的使用不會觸發任何事件,容易產生資料的異常。


4.3.2  previous和previousAttributes方法返回資料

1.功能描述

    在構建並例項化一個模型物件後,第一次使用set方法重置物件的全部屬性值,並將重置後物件的previousAttributes輸出至瀏覽器的控制檯中。接下來,第二次使用set方法重置物件的全部屬性值,同時將重置後物件的previousAttributes輸出至瀏覽器的控制檯中,觀察兩次輸出的變化。

var student = Backbone.Model.extend({
	initialize:function(){
		//建構函式
	},
	defaults:{
		Code:"10001",
		Name:"張三",
		Score:100
	}
});
var stuE = new student();
stuE.set({
	Code:"10106",
	Name:"皮卡丘",
	Score:650
});
console.log(stuE.toJSON());
console.log(stuE.previousAttributes());
console.log("-----");
stuE.set({
	Code:"10107",
	Name:"傑尼龜",
	Score:720
});
console.log(stuE.toJSON());
console.log(stuE.previousAttributes());

2.原始碼分析

    在上述程式碼中,首先第一次使用set方法重置stuE物件屬性值,分別呼叫物件的toJSON和previousAttributes方法輸出物件當前資料和上一個狀態的資料。然後,第二次使用set方法重置stuE物件屬性值,再次呼叫相關方法輸出物件當前資料和上一個狀態的資料。

    從上圖中可以看出,第2行顯示的物件值是第1行重置資料之前的狀態資料,即初始化資料。而再次重置資料之後,previousAttributes方法獲取的資料值也隨之發生了變化。圖中第5行顯示的物件值是第4行重置資料之前的狀態資料,即第一次呼叫物件set方法重置後的資料。由此可見,previousAttributes方法總是獲取物件重置資料之前的上一個狀態資料,而非初始化的資料。


4.3.3 set方法的內部順序(略)


4.4 同步資料到伺服器

    在Backbone中,客戶端的靜態頁面與伺服器之間的資料,可以通過save、fetch、destory方法分別實現在伺服器中儲存、獲取、刪除資料的操作,通過這些方法可以實現客戶端與伺服器之間的無縫式連線,完成客戶端資料與伺服器的同步。接下來逐一進行介紹。


4.4.1 save方法

    在Backbone中,物件save方法的功能是在伺服器中儲存客戶端傳送的資料,在資料傳送過程中,還能通過模型內部的isNew方法檢測資料是否是新建還是更新。如果是新建立,通過POST方法傳送,否則通過PUT方式傳送。伺服器根據資料傳送的方式進行資料新增或更新操作,並向客戶端返回操作結果,客戶端根據獲取的操作結果,進行下一步的操作。

    示例4-13 使用save方法傳送資料

    當一個例項化後的模型物件在模型中設定伺服器請求地址url屬性後,就可以直接呼叫物件的save方法,向伺服器傳送資料。接下來通過簡單的示例來演示save方法向伺服器傳送資料的過程。

1.功能描述

    首先,在構建模型類時新增url屬性,指定save方法傳送資料時的請求路徑。然後例項化一個模型物件,並呼叫該物件的save方法,此時觀察瀏覽器控制檯的資料請求。

var student = Backbone.Model.extend({
	initialize:function(){
		//建構函式
	},
	url:"../servlet/StudentServlet",
	defaults:{
		Code:"10001",
		Name:"張三",
		Score:100
	}
});
var stuE = new student();
stuE.set({
	Code:"10107",
	Name:"皮卡丘",
	Score:750
});
stuE.save();

3.頁面效果

    在上述程式碼中,首先在模型中新增一個用於執行伺服器請求地址的url屬性,並設定該屬性的值。然後,呼叫物件的set方法重置一次模型物件的屬性值,並呼叫save方法進行資料儲存。在儲存過程中,將向已設定的url屬性值傳送本次重置的物件資料,儲存至伺服器中。執行上述程式碼之後,在Firefox瀏覽器控制檯獲取的請求資料效果如上圖所示。

4.原始碼分析

    從上圖可以看出,此次呼叫save方法傳送資料的方式因為是新增加資料,所以是POST方式。請求返回200,表示此次資料傳送的請求地址是成功的。另外,資料傳送的格式是JSON,資料內容為最後一次使用set方法重置的屬性值。


    示例4-14 使用save方法接收返回值

    使用物件的save方法傳送資料至伺服器後,伺服器將接收到的資料寫入資料庫,實現儲存或修改的功能。操作完成後,將向客戶端返回一個成功或失敗的標誌,客戶端根據這一返回值進行下一步的操作。

1.功能描述

    在示例4-13的基礎之上修改程式碼,呼叫save方法傳送資料時,新增一個success函式,通過該函式的引數可以傳回伺服器的返回值。獲取成功後,將返回值的內容輸出至瀏覽器的控制檯中。

var student = Backbone.Model.extend({
	initialize:function(){
		//建構函式
	},
	url:"../servlet/StudentServlet",
	defaults:{
		Code:"10001",
		Name:"張三",
		Score:100
	}
});
var stuE = new student();
stuE.set({
	Code:"10107",
	Name:"皮卡丘",
	Score:750
});
stuE.save(null,{
	success:function(model,response){
		console.log(response);	
	}
});
伺服器端程式碼

import java.io.IOException;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import net.sf.json.JSONObject;

public class StudentServlet extends HttpServlet {

	public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		String code = request.getParameter("Code");
		String name = request.getParameter("Name");
		String score = request.getParameter("Score");
		System.out.println("code---->"+code);
		System.out.println("name---->"+name);
		System.out.println("score---->"+score);
		JSONObject jsonObject = new JSONObject();
		jsonObject.put("code", "777");
//		response.getWriter().println("{\"code\":\"888\"}");//注意JSON資料必須鍵值都帶雙引號
		response.getWriter().println(jsonObject.toString());
	}

	public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		doGet(request, response);
	}
}

2.頁面效果

    本次修改的前端頁面程式碼中,在呼叫物件的save方法時,設定一個success函式,當成功接收伺服器返回值時自動執行。在該函式中,通過response引數獲取伺服器返回的JSON格式資料,並將該值顯示在瀏覽器的控制檯中。最終在Firefox瀏覽器控制檯輸出效果如上圖所示。

3.原始碼分析

    從上圖中可以看出,服務請求是正確的,並有響應,響應為JSON格式的資料,客戶端通過在success函式的引數response獲取該返回的code值;此外,也可以在save方法中新增一個error函式,當伺服器出現返回錯誤時執行該函式。



    示例4-15 使用save方法時設定wait設定
    在呼叫save方法向伺服器儲存資料時,不僅可以在配置物件中新增success或error函式,還可以將wait屬性值設定為true。在配置物件中,將wait屬性值設定為true時,將會呼叫validate方法,對傳送資料的有效性進行驗證。如果沒有通過驗證,將不會向伺服器傳送資料,而物件的資料會進行回滾,返回上一狀態。此外,當向伺服器傳送資料時,如果請求失敗也將導致資料回滾,返回上一狀態。

1.功能描述

    是示例4-14的基礎之上修改程式碼。首先,呼叫save方法傳送資料請求時,將配置物件中的wait屬性值設定為true或不設定該屬性;然後分別在瀏覽器的控制檯中觀察這兩種不同設定情況下資料傳送的內容。

var student = Backbone.Model.extend({
	initialize:function(){
		//建構函式
	},
	url:"haha",//不可訪問的url
	defaults:{
		Code:"10001",
		Name:"張三",
		Score:100
	}
});
var stuE = new student();
stuE.save({
	Code:"10107",
	Name:"皮卡丘",
	Score:750
},{
	success:function(model,response){
		console.log(response);
	},
	wait:true
});
console.log(stuE.attributes);

當wait屬性為true時



當wait屬性為false時


2.原始碼分析

    在上述程式碼中,首先將模型中的url屬性設定為一個不可訪問的伺服器地址,造成請求異常。呼叫save方法向伺服器傳送資料時,直接通過該方法的第一個引數進行設定併傳送,並在save方法的可選引數中新增success函式,將wait屬性設定為true,表示需要驗證才能更新模型中資料。最後,在瀏覽器的控制檯中,以JSON的格式輸出物件stuE的全部資料。

    從上圖中可以看出,向伺服器傳送資料的請求地址異常時,如果在save方法中將wait屬性值設定為true時,資料將進行回滾;如果沒有設定wait屬性,不論伺服器是否接收或傳送資料是否符合驗證規則,都將原有資料進行重置,更新為最新的物件資料。

    通過本示例的演示可以看出,通過呼叫save方法中的第一個引數,可以實現既向伺服器傳送資料,又重置本地模型資料的功能。該引數可以通過物件的方式重置多個屬性,也可以通過呼叫兩個引數,採用key/value的方式實現某個屬性值的傳送與重置。


4.4.2 fetah方法

    與save方法不同,fetah方法的功能是從伺服器端獲取資料,常用於資料模型初始化或資料恢復,它的使用格式與save方法差不多,該方法採用get方式請求伺服器中的資料,當請求成功後,將呼叫set方法重置模型的this.attributes物件。同時,如果重置成功,呼叫success函式,否則直接返回。下面通過一個簡單的示例來演示fetch方法從伺服器獲取資料的過程。

    示例4-16 使用fetch方法獲取伺服器資料

1.功能描述

    在構建模型類時,首先設定url屬性,用於指定fetch方法獲取資料時的請求路徑。然後例項化一個模型物件,並呼叫該物件的fetch方法。在呼叫過程中,新增該方法的兩個回撥函式success和error,在第一個函式中,通過瀏覽器的控制檯輸出獲取的資料內容。

var student = Backbone.Model.extend({
	initialize:function(){
		//建構函式
	},
	url:"../servlet/StudentServlet"
});
var stuE = new student();
stuE.fetch({
	success:function(model,response){
		console.log(stuE.toJSON());
	},
	error:function(err){
		console.log(err);
	}
});

2.原始碼分析

    在本次示例的前端頁面程式碼中,首先通過在資料模型中新增一個url屬性值,來設定fetch方法請求資料的地址。然後,例項化一個模型資料物件,並呼叫該物件的fetch方法按指定的url路徑獲取伺服器返回的資料。最後,在fetch方法的配置物件中新增一個success函式,資料請求成功後呼叫該函式,將當前stuE物件的內容以JSON格式輸出在瀏覽器的控制檯。

    從上圖中可以看出,當物件呼叫fetch方法請求資料成功時,已將伺服器端的JSON格式資料通過呼叫set方法重置於當前的資料模型中,因此可以呼叫toJSON方法將物件stuE的資料以JSON格式輸出在控制檯中。


4.4.3 destory方法

    在Backbone中,當呼叫物件的destory方法時,將以DELETE請求方式向伺服器傳送物件的ID資料,伺服器接收該資料後刪除對應的資料記錄,並向客戶端傳送刪除成功的標誌。

    由於是刪除物件的資料,因此在呼叫destroy方法時,必須傳送ID號屬性,如果不存在該屬性,可以通過idAttribute屬性進行設定,否則不會傳送資料請求操作。

    此外,在呼叫destroy方法的過程中,也可以配置物件中新增success、error函式或將wait屬性值設定為true,當請求伺服器刪除資料成功並接收返回值後,不僅觸發繫結的destroy事件,而且還呼叫success函式;當請求伺服器失敗時,如果wait屬性值為true,則不會觸發繫結的destroy事件,反之將會觸發繫結的destroy事件並且執行error方法,下面通過一個簡單的示例來演示destroy方法從伺服器刪除資料的過程。


    示例4-17 使用destroy方法從伺服器刪除資料

1.功能描述

    在構建模型類時,首先通過url屬性指定刪除資料的請求路徑,並新增idAttribute屬性指定ID對應的屬性名稱。然後例項化一個模型物件,並呼叫該物件的destroy方法。在呼叫該方法時,通過success回撥函式獲取請求傳回的內容,並將內容輸出至於瀏覽器控制檯中。

var student = Backbone.Model.extend({
	//建構函式
	initialize:function(){
		this.on("destroy",function(){
			console.log("正在呼叫destroy方法");
		});
	},
	url:"../servlet/StudentDeleteServlet",
	idAttribute:"Code"
});
var stuE = new student({
	Code:"10107"
});
stuE.destroy({
	success:function(model,response){
		if(response.code=="0"){
			console.log("Code為"+model.get("Code")+"的資料已刪除");
		}
	},
	error:function(err){
		console.log("資料刪除異常");
	},
	wait:true
});
伺服器端程式碼
import java.io.IOException;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import net.sf.json.JSONObject;

public class StudentDeleteServlet extends HttpServlet {

	/**
	 * 注意因為是DELETE請求,所以不是用doGet和doPost來處理這個請求了
	 */
	@Override
	public void doDelete(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		JSONObject jsonObject = new JSONObject();
		jsonObject.put("code", "0");
		response.getWriter().print(jsonObject.toString());
	}

}


當URL正確時


當URL錯誤時


2.原始碼分析

    在本示例的前端頁面程式碼中,首先為了向服務端傳送刪除資料的ID號,通過idAttribute屬性將Code名稱設定為資料請求時的ID號屬性。然後,在建構函式中繫結destroy事件,當刪除資料請求成功開始刪除本地模型中對應資料時,將會觸發該事件。

    最後,例項化一個名稱為stuE的物件,並呼叫該物件的destroy方法。在呼叫方法的過程中,新增了success和error函式,並將wait屬性值設定為true,當伺服器成功刪除指定ID號的資料時,執行success函式。在該函式中,根據伺服器返回的標誌值將在瀏覽器的控制檯中輸出刪除成功的資訊。

    當伺服器成功刪除資料並向客戶端返回刪除成功標誌後,客戶端進行本地模型資料的刪除,此時會觸發已繫結的destroy事件然後執行success函式,根據服務端返回的標誌,在瀏覽器的控制檯輸出刪除成功的資訊。

    當請求伺服器刪除資料出現異常時,由於在destroy方法中配置物件的wait屬性設定為true,因此不會觸發已繫結的destroy事件,只執行error函式,將錯誤資訊輸出至瀏覽器的控制檯中。

相關文章