事件設計概述
事件機制可以使程序邏輯更加符合現實世界,在JavaScript中很多對象都有自己的事件,例如按鈕就有onclick事件,下拉列表框就有onchange事件,通過這些事件可以方便編程。那么對于自己定義的類,是否也可以實現事件機制呢?是的,通過事件機制,可以將類設計為獨立的模塊,通過事件對外通信,提高了程序的開發效率。本節就將詳細介紹JavaScript中的事件設計模式以及可能遇到的問題。
最簡單的事件設計模式
最簡單的一種模式是將一個類的方法成員定義為事件,這不需要任何特殊的語法,通常是一個空方法,例如:
function class1(){
//構造函數
}
class1.prototype={
show:function(){
//show函數的實現
this.onShow(); //觸發onShow事件
},
onShow:function(){} //定義事件接口
}
上面的代碼中,就定義了一個方法:show(),同時該方法中調用了onShow()方法,這個onShow()方法就是對外提供的事件接口,其用法如下:
//創建class1的實例
var obj=new class1();
//創建obj的onShow事件處理程序
obj.onShow=function(){
alert("onshow event");
}
//調用obj的show方法
obj.show();
由此可見,obj.onShow方法在類的外部被定義,而在類的內部方法show()中被調用,這就實現了事件機制。
上述方法很簡單,實際的開發中常用來解決一些簡單的事件功能。說它簡單,因為它有以下兩個缺點:
? 不能夠給事件處理程序傳遞參數,因為是在show()這個內部方法中調用事件處理程序的,無法知道外部的參數;
? 每個事件接口僅能夠綁定一個事件處理程序,而內部方法則可以使用attachEvent或者addEventListener方法綁定多個處理程序。
在下面兩小節將著重解決這個問題。
給事件處理程序傳遞參數
給事件處理程序傳遞參數不僅是自定義事件中存在的問題,也是系統內部對象的事件機制中存在的問題,因為事件機制僅傳遞一個函數的名稱,不帶有任何參數的信息,所以無法傳遞參數進去。例如:
//定義類class1
function class1(){
//構造函數
}
class1.prototype={
show:function(){
//show函數的實現
this.onShow(); //觸發onShow事件
},
onShow:function(){} //定義事件接口
}
//創建class1的實例
var obj=new class1();
//創建obj的onShow事件處理程序
function objOnShow(userName){
alert("hello,"+userName);
}
//定義變量userName
var userName="jack";
//綁定obj的onShow事件
obj.onShow=objOnShow; //無法將userName這個變量傳遞進去
//調用obj的show方法
obj.show();
注意上面的obj.onShow=objOnShow事件綁定語句,不能為了傳遞userName變量進去而寫成:
obj.onShow=objOnShow(userName);
或者:
obj.onShow="objOnShow(userName)";
前者是將objOnShow(userName)的運行結果賦給了obj.onShow,而后者是將字符串“objOnShow(userName)”賦給了obj.onShow。
要解決這個問題,可以從相反的思路去考慮,不考慮怎么把參數傳進去,而是考慮如何構建一個無需參數的事件處理程序,該程序是根據有參數的事件處理程序創建的,是一個外層的封裝。現在自定義一個通用的函數來實現這種功能:
//將有參數的函數封裝為無參數的函數
function createFunction(obj,strFunc){
var args=[]; //定義args用于存儲傳遞給事件處理程序的參數
if(!obj)obj=window; //如果是全局函數則obj=window;
//得到傳遞給事件處理程序的參數
for(var i=2;i<arguments.length;i++)args.push(arguments[i]);
//用無參數函數封裝事件處理程序的調用
return function(){
obj[strFunc].apply(obj,args); //將參數傳遞給指定的事件處理程序
}
}
該方法將一個有參數的函數封裝為一個無參數的函數,不僅對全局函數適用,作為對象方法存在的函數同樣適用。該方法首先接收兩個參數:obj和strFunc,obj表示事件處理程序所在的對象;strFunc表示事件處理程序的名稱。除此以外,程序中還利用arguments對象處理第二個參數以后的隱式參數,即未定義形參的參數,并在調用事件處理程序時將這些參數傳遞進去。例如一個事件處理程序是:
someObject.eventHandler=function(_arg1,_arg2){
//事件處理代碼
}
應該調用:
createFunction(someObject,"eventHandler",arg1,arg2);
這就返回一個無參數的函數,在返回的函數中已經包括了傳遞進去的參數。如果是全局函數作為事件處理程序,事實上它是window對象的一個方法,所以可以傳遞window對象作為obj參數,為了更清晰一點,也可以指定obj為null,createFunction函數內部會自動認為該函數是全局函數,從而自動把obj賦值為window。下面來看應用的例子:
<script language="JavaScript" type="text/javascript">
<!--
//將有參數的函數封裝為無參數的函數
function createFunction(obj,strFunc){
var args=[];
if(!obj)obj=window;
for(var i=2;i<arguments.length;i++)args.push(arguments[i]);
return function(){
obj[strFunc].apply(obj,args);
}
}
//定義類class1
function class1(){
//構造函數
}
class1.prototype={
show:function(){
//show函數的實現
this.onShow(); //觸發onShow事件
},
onShow:function(){} //定義事件接口
}
//創建class1的實例
var obj=new class1();
//創建obj的onShow事件處理程序
function objOnShow(userName){
alert("hello,"+userName);
}
//定義變量userName
var userName="jack";
//綁定obj的onShow事件
obj.onShow=createFunction(null,"objOnShow",userName);
//調用obj的show方法
obj.show();
//-->
</script>
在這段代碼中,就將變量userName作為參數傳遞給了objOnShow事件處理程序。事實上,obj.onShow得到的事件處理程序并不是objOnShow,而是由createFunction返回的一個無參函數。
通過createFunction封裝,就可以用一種通用的方案實現參數傳遞了。這不僅適用于自定義的事件,也適用于系統提供的事件,其原理是完全相同的。
使自定義事件支持多綁定
可以用attachEvent或者addEventListener方法來實現多個事件處理程序的同時綁定,不會互相沖突,而自定義事件怎樣來實現多訂閱呢?下面介紹這種實現。要實現多訂閱,必定需要一個機制用于存儲綁定的多個事件處理程序,在事件發生時同時調用這些事件處理程序。從而達到多訂閱的效果,其實現如下:
<script language="JavaScript" type="text/javascript">
<!--
//定義類class1
function class1(){
//構造函數
}
//定義類成員
class1.prototype={
show:function(){
//show的代碼
//...
//如果有事件綁定則循環onshow數組,觸發該事件
if(this.onshow){
for(var i=0;i<this.onshow.length;i++){
this.onshow[i](); //調用事件處理程序
}
}
},
attachOnShow:function(_eHandler){
if(!this.onshow)this.onshow=[]; //用數組存儲綁定的事件處理程序引用
this.onshow.push(_eHandler);
}
}
var obj=new class1();
//事件處理程序1
function onShow1(){
alert(1);
}
//事件處理程序2
function onShow2(){
alert(2);
}
//綁定兩個事件處理程序
obj.attachOnShow(onShow1);
obj.attachOnShow(onShow2);
//調用show,觸發onshow事件
obj.show();
//-->
</script>
從代碼的執行結果可以看到,綁定的兩個事件處理程序都得到了正確的運行。如果要綁定有參數的事件處理程序,只需加上createFunction方法即可,在上一節有過描述。
這種機制基本上說明了處理多事件處理程序的基本思想,但還有改進的余地。例如如果類有多個事件,可以定義一個類似于attachEvent的方法,用于統一處理事件綁定。在添加了事件綁定后如果想刪除,還可以定義一個detachEvent方法用于取消綁定。這些實現的基本思想都是對數組的操作。
posted on 2007-10-09 09:41
lk 閱讀(262)
評論(0) 編輯 收藏 所屬分類:
ajax&js