Backbine.js實戰第三章----事件管理

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

3.2基本事件方法

3.2.1 繫結on方法

使用on方法可以給一個物件的自定義事件繫結觸發該事件時執行的函式,當自定義的事件觸發時,繫結的函式將會被執行。其呼叫格式如下所示。

obj.on(eventName,function,[context]);

其中,引數Obj表示物件本身;eventName表示自定義的事件名;function表示當事件觸發時,被執行的函式;可選引數context表示上下文物件,用於物件級事件的監聽,即當一個物件需要監聽另一個物件的事件時,可以使用該引數。

使用on方法不僅可以繫結使用者的自定義事件,還可以監聽物件自帶的一些事件,接下來通過簡單事例來進一步瞭解該方法的使用過程。

示例3-1 使用on方法監聽預設事件

1.功能描述

構建一個名為“person”的模型類,在構建時,通過defaults設定物件的預設屬性名稱,使用on方法繫結物件預設屬性的change事件。當重置物件預設屬性值時觸發該事件,並在瀏覽器的控制檯中輸出“物件的預設值發生了變化”的字樣。

2.實現程式碼

var person = Backbone.Model.extend({
	defaults:{
		name:"",
		sex:""
	}
});
var man = new person();
man.on("change",function(){
	console.log("物件的預設值發生了變化");
});
man.set("name:","皮卡丘");

3.原始碼分析

  在上述程式碼中,首先定義一個名為person的資料模型類。在定義時,通過defaults方法設定兩個名稱為“name”和“sex”的預設資料項,並將它們的值設定空。

  然後,例項化一個名為man的模型類物件,並使用on方法向該物件繫結觸發change事件時執行的函式。在該函式中,將在瀏覽器的控制檯輸出“物件的預設值發生了變化”字樣。即只要物件的屬性值發生了變化,將觸發change事件,便執行事件繫結的函式。

  最後,使用物件的set方法,重置一個name屬性值,一旦修改物件的屬性值,將會觸發繫結的change事件。因此,當執行重置屬性值程式碼之後,將會在瀏覽器的控制檯輸出通知文字。


示例3-2 使用on方法監聽預設事件

在使用on方法監聽物件的change事件時,還可以監聽到某個屬性值的變化事件,即屬性事件。其呼叫格式如下。

obj.on(eventName:attrName,function(model,value))

其中,引數attrName表示物件中的屬性名稱;冒號(:)是過濾符,表示它是一個只針對某屬性變化時觸發的事件。在觸發事件後的回撥函式中,引數model是當前的資料模型物件,value表示名為attrName的屬性修改後的值。接下來通過簡單的程式碼來說明屬性事件的觸發過程。


1.功能描述

在3-1的基礎之上,使用on方法繫結物件中sex屬性的change事件,當sex屬性值發生變化時觸發該事件,並在瀏覽器的控制檯中輸出變化後的最新值。

2.實現程式碼

var person = Backbone.Model.extend({
	defaults:{
		name:"",
		sex:"女"
	}
});
var man = new person();
man.on("change",function(){
	console.log("物件的預設值發生了變化");
});
man.on("change:sex",function(model,value){
	console.log("您修改了性別屬性值,最新值是:"+value);
});
man.set("sex","男");


3.原始碼分析

在上述程式碼中,分別給物件man繫結了兩個事件,一個是預設事件change,另一個是屬性事件change:sex,即sex屬性變化事件。在屬性變化事件的回撥函式中,通過回傳的value引數獲取最新修改後的屬性值,並顯示在瀏覽器的控制檯中。

最後執行物件的set方法時,在Backbone內部會對已變化的值進行檢測,當屬性值與上次的值不同時,將會觸發設定的屬性事件和預設的change事件。

注意:

從上圖可以看出,當修改物件的某個屬性值時,其事件觸發的順序是:先觸發屬性事件,然後才觸發預設的change事件,這一點需要注意。


示例3-3 使用on方法獲取屬性修改前的值

在使用on方法繫結change和change屬性事件時,還可以通過回撥函式中的model物件獲取屬性修改前的所有值,獲取方法如下程式碼所示。

model.previous("attrName")

model.previousAttributes()

在上述程式碼中,previous()方法是獲取物件中某個屬性的原有值,previousAttributes()方法則返回一個物件,物件中包含上一個儲存狀態所有屬性的原有值。這兩個方法只用於模型物件的change和change屬性事件中獲取上一個儲存狀態的屬性值。接下來通過一個簡單的示例來演示這兩個方法的使用過程。


1.功能描述

分別繫結“分數”、“年齡”屬性的change事件。在事件中,分別將屬性重置前後的值進行對比,並根據對比值的不同在瀏覽器的控制檯中分別輸出不同的內容。

2.實現程式碼

var person = Backbone.Model.extend({
	defaults:{
		name:"",
		sex:"女",
		age:32,
		score:120
	}
});
var man = new person();
man.on("change:score",function(model,value){
	var oldScore = model.previous("score");//獲得修改前的指定屬性
	if(value>oldScore){
		console.log("您比上次進步了"+(value-oldScore)+"分");
	}else if(oldScore>value){
		console.log("您比上次落後了"+(oldScore-value)+"分");
	}else{
		console.log("您的成績沒有變化");
	}
});
man.on("change:age",function(model,value){
	var objAttr = model.previousAttributes();//獲得修改前的物件
	var oldAge = objAttr.age;
	if(value>oldAge){
		console.log("您又年長了"+(value-oldAge)+"歲");
	}else if(oldAge>value){
		console.log("您又年輕了"+(oldAge-value)+"歲");
	}else{
		console.log("您的年齡沒有變化");
	}
});
man.set({"age":36,"score":200});


3.原始碼分析

    在上述程式碼中,通過使用on方法分別繫結物件man的change:score和change:age兩個屬性事件。

    在第一個屬性事件change:score中,通過回撥函式中model模型物件的previous()方法,獲取上一次儲存的score屬性值,並儲存至變數oldScore中;將oldScore變數與最新修改的score屬性值value進行比較,根據比較的結果,在瀏覽器的控制檯中輸出不同的文字。

    在第二個屬性事件change:age中,通過回撥函式中model模型物件的previousAttributes()方法,獲取上一次儲存結果的物件,並將該物件儲存至變數objAttr中;再通過訪問物件變數objAttr屬性的方式,獲取上一次儲存的age屬性值,並儲存至oldAge中。接下來的程式碼功能與change:score屬性事件相同,不再贅述。

    繫結兩個屬性事件之後,通過呼叫man物件的set方法,重置了age,score兩個屬性值,導致了這兩個事件的觸發。

    從上圖可以看出,預設age屬性值為32,而重置時的屬性值為36,它們之間相差4歲,所以在瀏覽器的控制檯中顯示“您又年長了4歲”。score屬性與age屬性事件過程基本一樣,不再贅述。


示例3-4 使用on方法繫結多個事件

1.功能描述

    在Backbone中,除了使用on方法繫結單個物件的事件,還可以使用該方法同時繫結多個物件的事件。繫結的格式有兩種,第一種為各個事件使用空格隔開,格式如下。

obj.on(eventName1 eventName2,function);

    其中,使用空格隔開的引數eventName1和eventName2表示被繫結的多個事件名稱,function表示所有被繫結事件都要執行的自定義函式。接下來通過一個簡單的示例來說明如何獲取重置時的原值與重置後的新值,並將它們輸出至瀏覽器的控制檯中。

var person = Backbone.Model.extend({
	defaults:{
		name:"張三",
		sex:"女",
		age:20,
		score:30
	}
});
var man = new person();
man.on("change:score change:age",function(model,value){
	var oldAge = model.previous("age");
	var newAge = model.get("age");
	if(oldAge!=newAge){
		console.log("age原值:"+oldAge+",新值:"+newAge);
	}
	
	var oldScore = model.previous("score");
	var newScore = model.get("score");
	if(oldScore!=newScore){
		console.log("score原值:"+oldScore+",新值:"+newScore);
	}
});
man.set("age",36);
man.set("score",200);

2.原始碼分析

    在上述程式碼中,使用on方法分別繫結了物件man的兩個屬性事件change:score和change:age,在繫結事件執行的函式中,首先通過模型物件的previous和get方法獲取屬性修改前後的值,然後通過比較這兩個屬性值是否發生了變化,如果發生了變化,則在瀏覽器的控制檯中輸出該屬性的原值和新值。最後,通過呼叫man物件的set方法重置age和score屬性值。

    從上圖中in個,可以看出由於是按照先後順序對man物件的屬性值進行重置,因此,在控制檯顯示時,也是按照順序進行顯示的,如果不是按照先後順序,而是同時對兩個屬性值進行重置,重置屬性值程式碼修改如下。

man.set({"age":36,"score":200})

執行上述重置屬性值時,將會在控制檯輸出兩次一樣的結果,最終在Chrome瀏覽器控制檯輸出效果如下圖所示。


上圖重複輸出的原因在於,同時重置屬性值,導致在兩個屬性事件分別觸發的過程中,這兩個屬性的原值與新值都是不相同的,因此符合輸出顯示的條件。因為繫結兩個事件,所以出現了兩次重複的輸出。


    在使用on方法繫結事件中,有兩種格式可以繫結多個事件,除第一種使用空格之外,第二種方法為使用物件方式繫結多個事件,其呼叫格式如下。

var ObjEvent = {

       eventName1:function1,

       eventName2:function2

       ...

}

Obj,on(ObjEvent);

上述程式碼中,首先定義一個雜湊物件ObjEvent,並以ket/value的方式向該物件批量新增各個事件名稱和執行事件的函式,即引數eventName1和function1;然後通過使用on方法繫結該雜湊物件即可。

接下來將第一種使用空格方式繫結多個事件的程式碼修改成使用雜湊物件繫結多個事件的功能,修改程式碼如下所示。

var person = Backbone.Model.extend({
	defaults:{
		name:"張三",
		sex:"女",
		age:20,
		score:30
	}
});
var man = new person();
var objEvent = {
	"change:score":score_change,
	"change:age":age_change,
}
man.on(objEvent);
function score_change(model,value){
	var oldScore = model.previous("score");
	var newScore = model.get("score");
	if(oldScore!=newScore){
		console.log("score原值:"+oldScore+",新值:"+newScore);
	}
}

function age_change(model,value){
	var oldAge = model.previous("age");
	var newAge = model.get("age");
	if(oldAge!=newAge){
		console.log("age原值:"+oldAge+",新值:"+newAge);
	}
} 

man.set({"age":36,score:200});
在上述程式碼中,首先定義一個雜湊物件objEvent,在該物件中批量新增了模型物件man的兩個屬性事件change:score和change:age,並指定這兩個屬性事件執行的自定義函式分別為score_change和age_change,程式碼如下所示。

...

var objEvent = {

     "change:score":score_change,

     "change:age":age_change

}

...

然後,呼叫模型物件man的on方法繫結雜湊型別物件objEvent,從而完成物件多事件的繫結。最後,呼叫模型物件man的set方法重置物件的age和score兩個屬性值,導致對應繫結屬性事件的觸發,其最終在Chrome瀏覽器中執行的結果與上圖完全一致。


注意:

雖然使用上述兩種方式都可以繫結物件的多個事件,但這兩種方式也各具特點。在使用空格方式繫結多個事件時,需要考慮事件執行時的順序,有重複執行的可能性,因此適合多個事件執行一個函式的場景;而使用雜湊型物件的方式繫結多個事件時,每個事件所執行的函式都是一一對應的關係,程式碼機構非常清晰,因此適合不同事件執行不同函式的需求。



3.2.2 繫結一次once方法

在Backbone中,使用on方法可以繫結物件的事件之外,還可以使用once方法完成物件事件的繫結,只不過once方法繫結的事件只執行一次,之後即使觸發也不執行。其呼叫的格式如下。

Obj.once(eventName,function,[context])

其中,引數Obj表示物件本身,eventName表示自定義的事件名,function表示當前事件觸發時被執行的函式。接下來通過一個簡單示例介紹它的使用方法。

示例3-5 使用once方法繫結事件

1.功能描述

先使用模型物件的once物件繫結change事件。在該事件中,通過變數累計事件執行的次數,並將該次數內容輸出至瀏覽器的控制檯中,然後使用set方法重置二次模型物件的屬性。

var person = Backbone.Model.extend({
	defaults:{
		name:"",
		sex:"女",
		age:32,
		score:120
	}
});
var man = new person();
var intNum = 0;
man.once("change",function(){
	intNum++;
	console.log("事件觸發的次數為"+intNum);
});
man.set("age",36);
man.set("age",37);

2.原始碼分析

在上述程式碼中,首先定義資料模型並例項化一個模型物件man,定義一個用於記錄執行次數的全域性變數intNum,該變數的初始值為0;然後通過man物件呼叫once方法,繫結物件的change事件。在該事件執行的函式中,先累加變數intNum的值,即記錄該事件觸發的次數,並且在控制檯中輸出該累加的變數intNum值。最後,兩次呼叫man物件的set方法對age屬性進行重置,

從上圖看到,雖然執行了兩次的屬性重置操作,但繫結的change事件僅顯示一次,這是由於繫結事件時,使用了once方法,而非on方法,當執行once方法繫結物件的事件後,將會自動呼叫內部的_once()函式,僅執行一次物件繫結的事件,因此輸出的執行次數為1.針對once方法的這種特點,常常將該方法用於繫結物件的一些初始化事件中。


3.2.3 觸發事件trigger方法

    前面介紹瞭如何使用on或once方法繫結物件事件的過程,而這些事件都是物件本身自帶的系統事件,如change、change:age、change:score,它們的觸發都必須滿足相應的條件。例如change事件,當物件中的屬性值發生了變化時,才能觸發,其實也能通過呼叫一個方法來手動觸發某個事件,而這個方法就是trigger。

    trigger也是Backbone事件API中的一個重要方法,它的功能是觸發物件的某一個事件,呼叫格式如下所示。
Obj.trigger(eventName)
    其中,引數Obj表示物件本身,eventName表示自定義的事件名,即需要手動觸發的事件名稱。
    使用trigger方法可以手動觸發物件的任何事件,不僅是自帶的系統事件,還可以是自定義的事件,接下來通過一個簡單的例項介紹trigger方法的事件。

示例3-6 使用trigger方法觸發事件

 1.功能描述

    先使用on方法繫結模型物件的自定義事件change_age_sex和age屬性的change事件,然後分別呼叫trigger方法手動觸發繫結的事件。

var person = Backbone.Model.extend({
	defaults:{
		name:"",
		sex:"女",
		age:32,
		score:120
	}
});
var man = new person();
man.on("change_age_sex",function(){
	console.log("您手動觸發了一個自定義事件");
});
man.on("change:age",function(model,value){
	if(value!=undefined){
		console.log("您修改後的年齡為"+value);
	}else{
		console.log("您手動觸發了一個年齡修改事件");
	}
});
man.trigger("change_age_sex");
man.trigger("change:age");
man.set("age",37);

2.原始碼分析

在上述程式碼中,首先例項化了一個資料模型物件man,然後通過呼叫on方法為man物件繫結了change_age_sex自定義事件和change:age系統自帶事件。在change_age_sex自定義事件中,將通過瀏覽器的控制檯輸出一段說明文字;而在系統自帶的change:age事件中,將根據回撥函式value的值來判斷事件是否手動執行還是自動觸發。如果是手動執行,在控制檯中輸出一段說明文字,否則輸出修改後的age屬性值。最後,分兩次呼叫man物件的trigger方法手動觸發自定義事件change_age_sex和系統自帶事件change:age,同時使用set方法重置man物件的age屬性值,導致change:age的自動觸發。

從上圖中看到,使用trigger方法手動觸發change_age_sex事件時,在瀏覽器的控制檯輸出對應的說明文字。同樣,在手動觸發change:age事件時,在執行事件的程式碼中已通過回撥函式value值檢測出是否手動觸發,因此只在瀏覽器的控制檯輸出對應的說明文字。然後,第三次通過set方法自動觸發change:age事件時,在瀏覽器的控制檯中則輸出了修改後的age屬性值37.


3.2.4 移除事件off方法

在Backbone中,與繫結事件的on方法相對應的是移除事件的off方法,該方法的功能是移除物件中已繫結的某個、多個或全部的事件。其呼叫格式如下。

Obj.off(eventName,function,[context])

其中,引數eventName表示被移除的繫結事件名稱,該名稱可以是單個也可以是多個,如果要移除多個事件,則用空格將事件名稱隔開。除了移除物件的繫結事件之外,還可以移除事件執行的函式。即通過引數function來表示被移除的事件函式名。另外,如果在呼叫off方法時不帶任何引數,表示移除物件的全部繫結事件。接下來通過簡單示例逐一進行介紹。


示例3-7 使用off方法移除物件的某個或多個繫結事件

在Backbone中,如果要移除物件的某個繫結事件,可以呼叫物件的off方法,指定需要移除的事件名稱;如果有多個事件名稱,則用空格隔開。

1.功能描述

先自定義兩個函式,用於模型物件的on方法繫結自定義事件時呼叫。先使用on方法繫結自定義的事件,又呼叫off方法移除已繫結的事件。最後,使用trigger方法手動觸發事件,觀察事件觸發時瀏覽器控制檯中輸出的內容。

var person = Backbone.Model.extend({
	defaults:{
		name:"",
		sex:"女",
		age:32,
		score:120
	}
});
var man = new person();
var m = 0;
var n = 0;
var callback_a = function(){
	m++;
	console.log("您執行a事件的次數為:"+m);
}
var callback_b = function(){
	n++;
	console.log("您執行b事件的次數為:"+n);
}
man.on("event_a",callback_a);
man.on("event_b",callback_b);
man.off("event_a");
man.trigger("event_a event_b");
man.off("event_a event_b");
man.trigger("event_a event_b");

2.原始碼分析

    在上述程式碼中,例項化一個man物件之後,首先定義兩個變數m、n,分別用於記錄執行不同事件的次數。其次自定義兩個事件執行函式callback_a和callback_b。在這兩個函式中,分別對m、n的值進行累加,並在瀏覽器的控制檯中輸出事件的名稱和累加後的值。

    最後,兩次使用物件的on方法分別繫結event_a和event_b事件,並首次呼叫物件的off方法移除繫結的event_a事件。接下來,首次呼叫物件的trigger方法觸發event_a和event_b事件,當完成trigge方法呼叫後,再次使用物件的off方法移除繫結的event_a和event_b事件。此時,物件man所繫結的兩個事件已經全部移除。

    從上圖中看到,雖然在程式碼中使用on方法繫結了event_a和event_b兩個自定義的事件,但是在第一次觸發這兩個事件之前,先通過off方法移除了event_a事件。因此,在第一次觸發已繫結的兩個事件時,實際上僅有event_b事件執行。

    在第二次呼叫trigger方法再次觸發這兩個事件之前,又通過off方法移除了event_a和event_b事件,因此,在第二次觸發兩個事件時,已經沒有任何事件被執行,最終只有event_b事件被執行一次。


示例3-8 使用off方法移除繫結事件的某個函式

在Backbone中,不僅可以呼叫物件的off方法移除已繫結的一個或多個事件,還可以移除繫結事件執行的某個函式。(一個事件可以繫結多個函式)

1.功能描述

在3-7的基礎之上,使用off方法移除已繫結的某個函式,並觀察在觸發繫結事件時瀏覽器的控制檯中輸出的內容。

var person = Backbone.Model.extend({
	defaults:{
		name:"",
		sex:"女",
		age:32,
		score:120
	}
});
var man = new person();
var m = 0;
var n = 0;
var callback_a = function(){
	m++;
	console.log("您執行a事件的次數為:"+m);
}
var callback_b = function(){
	n++;
	console.log("您執行b事件的次數為:"+n);
}
man.on("event_a",callback_a);
man.on("event_a",callback_b);
man.trigger("event_a");
man.off("event_a",callback_b);
man.trigger("event_a");

2.原始碼分析

首先要明白一點,一個事件可以繫結多個function。

由於event_a最開始繫結了callback_a和callback_b,所以在觸發evant_a的時候callback_a和callback_b函式都會觸發。

當執行man.off("event_a",callback_b);的時候表示移除事件event_a裡的指定函式callback_b,此時event_a裡只有繫結了函式callback_b

所以再次執行事件event_a的時候只執行了callback_b。


示例3-9 使用off方法移除物件的全部繫結事件

在Backbone中,物件的off除了可以移除某個或多個事件、事件執行的函式外,還可以通過不帶引數的方法移除全部已繫結的事件,呼叫格式如下所示。

Obj.off();

1.功能描述

在示例3-7的基礎之上,先呼叫off方法移除全部已繫結的事件,然後呼叫trigger方法手動觸發這些事件,觀察瀏覽器控制檯中內容輸出的變化。

var person = Backbone.Model.extend({
	defaults:{
		name:"",
		sex:"女",
		age:32,
		score:120
	}
});
var man = new person();
var m = 0;
var n = 0;
var callback_a = function(){
	m++;
	console.log("您執行a事件的次數為:"+m);
}
var callback_b = function(){
	n++;
	console.log("您執行b事件的次數為:"+n);
}
man.on("event_a",callback_a);
man.on("event_a",callback_b);
man.off();
man.trigger("event_a event_b");

2.原始碼分析

執行修改的程式碼後在控制檯中不會輸出任何結果資訊。這是因為雖然使用物件的on方法繫結event_a和event_b這兩個事件,但在觸發這兩個繫結的事件之前,使用無參的方式呼叫了物件的off方法,將物件全部繫結的事件移除。因此,在執行時不會觸發任何事件。所以在控制檯中沒有任何資訊輸出。



3.3.1 監聽事件listenTo方法

Backbone的1.0版本中提供了監聽方法,在前面章節中提高的on等事件繫結方法,其實也是監聽方法的一種,只不過監聽的物件不同,物件的on方法用於監聽物件某事件的觸發,即物件觸發了這個事件,便執行相應的程式碼。

相對於物件的on方法而言,listenTo方法的監聽效果更為突出,它是一個物件監聽另一個物件的事件,如果被監聽的物件出發了被監聽的事件,執行相應的回撥函式或程式碼塊。例如,view物件要監聽mode物件的change事件,如果mode物件觸發了change事件,則需要重新整理當前view物件,即執行下列監聽方法的程式碼。

view.listenTo(model,'change',view.render);

上述監聽方法也等價於如下程式碼。

model.on('change',view.render,view);

其中,第三個引數為上下文環境物件,此時它的值為view,即model物件在觸發change事件時,關聯view物件進行執行view.render動作。

通過上述對listenTo方法的簡單介紹,我們知道它是一個物件級別的事件監聽方法,即在執行該方法時,必須具有兩個物件,其呼叫格式如下。

Obj1.listenTo(Obj2,EventName,function);

其中,引數Obj1、Obj2都為物件,引數EventName是Obj2物件觸發的事件名稱,引數function為當Obj2觸發指定的EventName事件時,Obj1所執行的自定義函式。接下來通過一個簡單的示例來演示listenTo方法的使用。


示例3-10 使用listenTo方法監聽事件

1.功能描述

先呼叫listenTo方法繫結模型物件age屬性的change事件。在該事件中,將會在瀏覽器的控制檯輸出重置age屬性時的原值與新值內容,然後呼叫set方法重置物件的age屬性。在瀏覽器控制檯輸出變化時的原值與新值內容。

var person = Backbone.Model.extend({
	defaults:{
		name:"",
		sex:"女",
		age:32,
		score:120
	}
});
var man = new person();
var obj = _.extend({},Backbone.Events);
obj.listenTo(man,"change:age",function(model,value){
	var oldage = model.previous("age");
	var newage = model.get("age");//value也是age最新值的意思
	if(oldage!=newage){
		console.log("age原值:"+oldage+",新值:"+newage);
	}
});
man.set("age",37);

2.原始碼分析

在上述程式碼中,首先例項化了一個model物件man外,並定義了另一個事件物件obj。然後呼叫obj物件的listenTo方法,監聽man物件的change:age事件。當觸發該事件時,獲取事件觸發前後的age屬性值,並進行比較。如果發生了 變化,則在瀏覽器的控制檯輸出原值和新值。最後呼叫man物件的set方法重置age屬性值,用於觸發change:age事件。

從上圖中看到,在一個物件使用listenTo方法監聽另一個物件的事件時,與物件本身呼叫on方法基本相同,同樣可以用過回撥函式獲取model物件和value新值,並通過比較是否變化後輸出在瀏覽器的控制檯中。


3.3.2 監聽一次listenToOnce方法

在Backbone中,除了使用listenTo方法進行物件級別事件的監聽外,還可以使用listenToOnce方法進行物件級別事件的監聽。這點類似於物件的on方法與once方法。物件的listenTo和listenToOnce方法最大的不同之處在於,前者是一個物件一直監聽另一個物件事件的觸發,而後者是僅監聽一次。其呼叫格式如下所示。

Obj1.listenToOnce(Obj2,EventName,function);

其中,引數的說明與listenTo完全一樣,不再贅述。接下來通過一個簡單示例來演示呼叫listenToOnce方法繫結物件的屬性事件。



示例3-11 使用listenToOnce方法監聽事件

1.功能描述

首先使用listenToOnce方法繫結物件age屬性的change事件。在該事件中,累計事件執行的次數,並將該次數的內容輸出至瀏覽器的控制檯中,然後呼叫set方法兩次重置age屬性值,觸發對應的change事件,觀察瀏覽器控制檯輸出內容的變化。

var person = Backbone.Model.extend({
	defaults:{
		name:"",
		sex:"女",
		age:32,
		score:120
	}
});
var man = new person();
var obj = _.extend({},Backbone.Events);
var intNum = 0;
obj.listenToOnce(man,"change:age",function(model,value){
	intNum++;
	console.log("事件觸發的次數為:"+intNum);
});
man.set("age",37);
man.set("age",38);

2.原始碼分析

在上述程式碼中,首先定義兩個用於監聽的物件man和obj,同時定義了一個名為intNum的變數,用於記錄事件觸發的次數。然後,呼叫obj物件的listenToOnce方法監聽man物件的change:age事件,當該事件觸發時,intNum變數累加一次值,在瀏覽器的控制檯中輸出累加後變數intNum的值。最後,再次呼叫man物件的set方法,重置man物件的age屬性值。

從上圖中看到,雖然在程式碼中兩次呼叫man物件執行set方法重置age屬性值,但是,在瀏覽器的控制檯中,事件觸發的次數顯示為1.這是由於obj物件使用了listenToOnce方法監聽man物件的change:age事件,而listenToOnce方法的功能是隻執行首次的監聽操作,後續事件即使觸發也不會監聽,因此瀏覽器的控制檯中顯示的事件觸發次數為1。



3.3.3 停止監聽 stopListening方法

在Backbone中,與單個物件的off方法相同,物件級別的事件監聽也有停止方法,即stopListening方法,其呼叫格式如下。

Obj1.stopListening(Obj2,EventName,function);

其中,引數Obj1和Obj2分別為監聽發起物件和被監聽物件,EventName引數為被監聽物件所促發的事件名稱,如果要停止監聽多個事件,可以在這個引數中使用空格號隔開。另一個引數function的作用是,當觸發監聽事件時,監聽發起物件執行的自定義函式名稱。在stopListening方法中,既可以停止被監聽物件的某個或多個事件的監聽,也可以通過引數function在被監聽物件的停止監聽事件觸發後,發起物件執行的自定義函式。此外,如果該方法不呼叫任何引數,表示停止監控全部已監控的物件事件。接下來通過一個簡單的示例來演示stopListening方法的使用。


示例3-12 使用stopListening方法停止監聽

1.功能描述

首先使用ListenTo方法,分別繫結物件name、age、score屬性的change事件,然後呼叫stopListening方法分別停止某個事件繫結的監聽,最後呼叫set方法重置屬性值時觸發繫結的事件,觀察瀏覽器控制檯輸出內容的變化。

var person = Backbone.Model.extend({
	defaults:{
		name:"",
		sex:"女",
		age:32,
		score:120
	}
});
var man = new person();
var obj = _.extend({},Backbone.Events);
obj.listenTo(man,"change:name",function(model,value){
	console.log("name修改後的值為:"+value);
});
obj.listenTo(man,"change:age",function(model,value){
	console.log("age修改後的值為:"+value);
});
obj.listenTo(man,"change:score",function(model,value){
	console.log("score修改後的值為:"+value);
});
//停止監聽某一個事件
obj.stopListening(man,"change:name");
man.set("name","張三");
man.set("age",35);
man.set("score",600);
//停止監聽兩個事件
obj.stopListening(man,"change:name change:age");
man.set("name","李四");
man.set("age",36);
man.set("score",601);
//停止監聽全部事件
obj.stopListening();
man.set("name","王二");
man.set("age",37);
man.set("score",602);

2.原始碼分析

    在上述程式碼中,首先定義了兩個物件man和obj,前者為被監聽物件,後者為監聽發起物件。然後,通過listenTo方法分別監聽man物件的change:age、change:age、change:score事件,當這些事件被觸發時,將在瀏覽器的控制檯輸出變化後的新值。最後,三次重置man物件的name、age、score屬性值。在第一次重置前,呼叫物件的stopListening方法停止監聽change:name事件;在第二次重置前,呼叫物件的stopListening方法停止監聽change:name和change:age事件;在第三次重置前,呼叫物件的stopListening方法停止全部監聽的事件。

    從上圖看到,當第一次重置man物件的name、age、score屬性值前,因為呼叫物件的stopListening方法停止監聽change:name事件,在瀏覽器的控制檯中顯示了age、score修改後的值35和600;而在第二次重置man物件的三個屬性值前,因為呼叫物件的stopListening方法停止監聽change:name和change:age事件,在瀏覽器的控制檯中顯示了score修改後的值601;而在第三次重置man物件的三個屬性值前,因為呼叫物件的stopListening方法停止全部的監聽事件,沒有在瀏覽器中輸出任何資訊。



3.4 其他事件

    在Backbone的事件API中,除了上述方法之外,還有一個比較特殊的事件——all,該事件無論在物件觸發任何自身事件或執行自定義函式時,都會執行。此外,在整個Backbone中Events佔有非常重要的地位,它以最小化模組的方式整合到Model、Collection、View類中,實現可以在這些類中自定義事件的功能,接下來詳細介紹這兩方面的知識。


3.4.1 特殊事件all的使用

   在Backbone中,all是一個很特殊的事件,因為該事件在物件的任何事件被觸發時,它都會自動觸發,可以說是一個全域性性的事件。此外,既然它是一個事件,也可以通過呼叫物件的trigger方法進行手動觸發;在觸發該事件時,還可以在回撥的函式中通過value引數獲取當前正在觸發的事件名稱。其呼叫的格式如下。

Obj.on("all",function);

   其中,使用on方法繫結了物件的on事件,當該事件觸發時,將執行自定義的回撥函式function。在該函式中,可以新增一個value引數,通過該引數獲取當前正在觸發事件的名稱。接下來通過一個簡單的示例來演示all事件的運用。


示例3-13 all事件的使用

1.功能描述

    首先使用on方法繫結物件name、age屬性的change事件和特殊的all事件,在這些事件中,都會向瀏覽器的控制檯輸出不同的內容。然後,呼叫set方法重置物件的屬性值,觸發對應的change事件,觀察瀏覽器控制檯輸出內容的變化。

var person = Backbone.Model.extend({
	defaults:{
		name:"",
		sex:"女",
		age:32,
		score:120
	}
});
var man = new person();
man.on("change:age",function(model,value){
	console.log("您觸發了change:age事件");
});
var event_fun = function(){
	console.log("您觸發了change:name事件");
}
man.on("change:name",event_fun);
man.on("all",function(value){
	console.log("您觸發了all事件中"+value);
});
man.set("name","皮卡丘");
man.set("age",35);

2.原始碼分析

    在上述程式碼中,首先例項化一個名為man的資料模型物件,然後呼叫物件的on方法繫結了change:age和change:name事件,並且還繫結了all事件。在繫結all事件中,通過回撥函式中的value引數獲取正在觸發的事件名稱,並在瀏覽器的控制檯中顯示該事件名稱;而在change:age和change:name事件中,分別在瀏覽器的控制檯中顯示相應觸發事件的名稱。最後,呼叫man物件的set方法分別重置物件自身的name、age屬性值。

    從上圖中看到,雖然只呼叫man方法重置了兩個屬性,但all事件卻被觸發了4次,這是由於每次重置物件屬性時,不僅觸發屬性事件,還要觸發change事件,這一點在到前面章解介紹change事件時已經介紹過。因此,當重置一個屬性值時,實際上觸發了兩個事件,由於每個事件觸發之後都會觸發all事件,所以all事件被觸發了4次。

    從上圖中還可以看出,all事件與其他事件在觸發上的順序,都是當其他事件觸發之後才觸發all事件。如果在一個事件中繫結了多個執行的自定義函式,而繫結的all事件觸發的順序也將是按照函式繫結時的順序依次觸發的。

    前面也提到過,作為一個事件同樣可以呼叫物件的trigger方法來觸發,而它觸發後輸出什麼內容呢?接下來,將程式碼清單3-13中最後兩句物件重置的程式碼修改為如下。

....省略部分程式碼

man.trigger("all");


    從上圖中看到,如果在沒有任何事件觸發的前提下,手動呼叫物件的trigger方法觸發all事件,同樣也會執行兩次。這是由於當呼叫trigger方法時,會呼叫兩次triggerEvents,一次為引數傳遞來的指定事件,另一次為固定的all事件。當沒有任何事件名稱傳遞過來時,其值為undefined,在Backbone框架內部的程式碼中,與all事件相關程式碼如下所示。

...

var events = this._events[name];

var allEvents = this._events.all;

if(events) triggerEvents(events,args);

if(allEvents) triggerEvents(allEvents,arguments);


相關文章