隨筆 - 154  文章 - 60  trackbacks - 0
          <2007年10月>
          30123456
          78910111213
          14151617181920
          21222324252627
          28293031123
          45678910

          聲明:

          該blog是為了收集資料,認(rèn)識(shí)朋友,學(xué)習(xí)、提高技術(shù),所以本blog的內(nèi)容除非聲明,否則一律為轉(zhuǎn)載!!

          感謝那些公開自己技術(shù)成果的高人們!!!

          支持開源,尊重他人的勞動(dòng)!!

          常用鏈接

          留言簿(3)

          隨筆分類(148)

          隨筆檔案(143)

          收藏夾(2)

          其他

          學(xué)習(xí)(技術(shù))

          觀察思考(非技術(shù))

          搜索

          •  

          最新評(píng)論

          閱讀排行榜

          評(píng)論排行榜

          事件設(shè)計(jì)概述
          事件機(jī)制可以使程序邏輯更加符合現(xiàn)實(shí)世界,在JavaScript中很多對(duì)象都有自己的事件,例如按鈕就有onclick事件,下拉列表框就有onchange事件,通過這些事件可以方便編程。那么對(duì)于自己定義的類,是否也可以實(shí)現(xiàn)事件機(jī)制呢?是的,通過事件機(jī)制,可以將類設(shè)計(jì)為獨(dú)立的模塊,通過事件對(duì)外通信,提高了程序的開發(fā)效率。本節(jié)就將詳細(xì)介紹JavaScript中的事件設(shè)計(jì)模式以及可能遇到的問題。

          最簡(jiǎn)單的事件設(shè)計(jì)模式
          最簡(jiǎn)單的一種模式是將一個(gè)類的方法成員定義為事件,這不需要任何特殊的語法,通常是一個(gè)空方法,例如:
          function class1(){
                //構(gòu)造函數(shù)
          }
          class1.prototype={
                show:function(){
                      //show函數(shù)的實(shí)現(xiàn)
                      this.onShow();  //觸發(fā)onShow事件
                },
                onShow:function(){}  //定義事件接口
          }
          上面的代碼中,就定義了一個(gè)方法:show(),同時(shí)該方法中調(diào)用了onShow()方法,這個(gè)onShow()方法就是對(duì)外提供的事件接口,其用法如下:
          //創(chuàng)建class1的實(shí)例
          var obj=new class1();
          //創(chuàng)建obj的onShow事件處理程序
          obj.onShow=function(){
                alert("onshow event");
          }
          //調(diào)用obj的show方法
          obj.show();

          由此可見,obj.onShow方法在類的外部被定義,而在類的內(nèi)部方法show()中被調(diào)用,這就實(shí)現(xiàn)了事件機(jī)制。
          上述方法很簡(jiǎn)單,實(shí)際的開發(fā)中常用來解決一些簡(jiǎn)單的事件功能。說它簡(jiǎn)單,因?yàn)樗幸韵聝蓚€(gè)缺點(diǎn):
          ? 不能夠給事件處理程序傳遞參數(shù),因?yàn)槭窃趕how()這個(gè)內(nèi)部方法中調(diào)用事件處理程序的,無法知道外部的參數(shù);
          ? 每個(gè)事件接口僅能夠綁定一個(gè)事件處理程序,而內(nèi)部方法則可以使用attachEvent或者addEventListener方法綁定多個(gè)處理程序。
          在下面兩小節(jié)將著重解決這個(gè)問題。

          給事件處理程序傳遞參數(shù)
          給事件處理程序傳遞參數(shù)不僅是自定義事件中存在的問題,也是系統(tǒng)內(nèi)部對(duì)象的事件機(jī)制中存在的問題,因?yàn)槭录C(jī)制僅傳遞一個(gè)函數(shù)的名稱,不帶有任何參數(shù)的信息,所以無法傳遞參數(shù)進(jìn)去。例如:
          //定義類class1
          function class1(){
                //構(gòu)造函數(shù)
          }
          class1.prototype={
                show:function(){
                      //show函數(shù)的實(shí)現(xiàn)
                      this.onShow();  //觸發(fā)onShow事件
                },
                onShow:function(){}  //定義事件接口
          }
          //創(chuàng)建class1的實(shí)例
          var obj=new class1();
          //創(chuàng)建obj的onShow事件處理程序
          function objOnShow(userName){
                 alert("hello,"+userName);
          }
          //定義變量userName
          var userName="jack";
          //綁定obj的onShow事件
          obj.onShow=objOnShow;  //無法將userName這個(gè)變量傳遞進(jìn)去
          //調(diào)用obj的show方法
          obj.show();
          注意上面的obj.onShow=objOnShow事件綁定語句,不能為了傳遞userName變量進(jìn)去而寫成:
          obj.onShow=objOnShow(userName);
          或者:
          obj.onShow="objOnShow(userName)";
          前者是將objOnShow(userName)的運(yùn)行結(jié)果賦給了obj.onShow,而后者是將字符串“objOnShow(userName)”賦給了obj.onShow。
          要解決這個(gè)問題,可以從相反的思路去考慮,不考慮怎么把參數(shù)傳進(jìn)去,而是考慮如何構(gòu)建一個(gè)無需參數(shù)的事件處理程序,該程序是根據(jù)有參數(shù)的事件處理程序創(chuàng)建的,是一個(gè)外層的封裝。現(xiàn)在自定義一個(gè)通用的函數(shù)來實(shí)現(xiàn)這種功能:
          //將有參數(shù)的函數(shù)封裝為無參數(shù)的函數(shù)
          function createFunction(obj,strFunc){
                var args=[];      //定義args用于存儲(chǔ)傳遞給事件處理程序的參數(shù)
                if(!obj)obj=window;     //如果是全局函數(shù)則obj=window;
                //得到傳遞給事件處理程序的參數(shù)
                for(var i=2;i<arguments.length;i++)args.push(arguments[i]);
                //用無參數(shù)函數(shù)封裝事件處理程序的調(diào)用
                return function(){
                      obj[strFunc].apply(obj,args); //將參數(shù)傳遞給指定的事件處理程序
                }
          }
          該方法將一個(gè)有參數(shù)的函數(shù)封裝為一個(gè)無參數(shù)的函數(shù),不僅對(duì)全局函數(shù)適用,作為對(duì)象方法存在的函數(shù)同樣適用。該方法首先接收兩個(gè)參數(shù):obj和strFunc,obj表示事件處理程序所在的對(duì)象;strFunc表示事件處理程序的名稱。除此以外,程序中還利用arguments對(duì)象處理第二個(gè)參數(shù)以后的隱式參數(shù),即未定義形參的參數(shù),并在調(diào)用事件處理程序時(shí)將這些參數(shù)傳遞進(jìn)去。例如一個(gè)事件處理程序是:
          someObject.eventHandler=function(_arg1,_arg2){
               //事件處理代碼
          }
          應(yīng)該調(diào)用:
          createFunction(someObject,"eventHandler",arg1,arg2);
          這就返回一個(gè)無參數(shù)的函數(shù),在返回的函數(shù)中已經(jīng)包括了傳遞進(jìn)去的參數(shù)。如果是全局函數(shù)作為事件處理程序,事實(shí)上它是window對(duì)象的一個(gè)方法,所以可以傳遞window對(duì)象作為obj參數(shù),為了更清晰一點(diǎn),也可以指定obj為null,createFunction函數(shù)內(nèi)部會(huì)自動(dòng)認(rèn)為該函數(shù)是全局函數(shù),從而自動(dòng)把obj賦值為window。下面來看應(yīng)用的例子:
          <script language="JavaScript" type="text/javascript">
          <!--
          //將有參數(shù)的函數(shù)封裝為無參數(shù)的函數(shù)
          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(){
                //構(gòu)造函數(shù)
          }
          class1.prototype={
                show:function(){
                      //show函數(shù)的實(shí)現(xiàn)
                      this.onShow();  //觸發(fā)onShow事件
                },
                onShow:function(){} //定義事件接口
          }
          //創(chuàng)建class1的實(shí)例
          var obj=new class1();
          //創(chuàng)建obj的onShow事件處理程序
          function objOnShow(userName){
                alert("hello,"+userName);
          }
          //定義變量userName
          var userName="jack";
          //綁定obj的onShow事件
          obj.onShow=createFunction(null,"objOnShow",userName);
          //調(diào)用obj的show方法
          obj.show();
          //-->
          </script>
          在這段代碼中,就將變量userName作為參數(shù)傳遞給了objOnShow事件處理程序。事實(shí)上,obj.onShow得到的事件處理程序并不是objOnShow,而是由createFunction返回的一個(gè)無參函數(shù)。
          通過createFunction封裝,就可以用一種通用的方案實(shí)現(xiàn)參數(shù)傳遞了。這不僅適用于自定義的事件,也適用于系統(tǒng)提供的事件,其原理是完全相同的。


          使自定義事件支持多綁定
          可以用attachEvent或者addEventListener方法來實(shí)現(xiàn)多個(gè)事件處理程序的同時(shí)綁定,不會(huì)互相沖突,而自定義事件怎樣來實(shí)現(xiàn)多訂閱呢?下面介紹這種實(shí)現(xiàn)。要實(shí)現(xiàn)多訂閱,必定需要一個(gè)機(jī)制用于存儲(chǔ)綁定的多個(gè)事件處理程序,在事件發(fā)生時(shí)同時(shí)調(diào)用這些事件處理程序。從而達(dá)到多訂閱的效果,其實(shí)現(xiàn)如下:
          <script language="JavaScript" type="text/javascript">
          <!--
          //定義類class1
          function class1(){
                //構(gòu)造函數(shù)
          }
          //定義類成員
          class1.prototype={
                show:function(){
                     //show的代碼
                     //...

                     //如果有事件綁定則循環(huán)onshow數(shù)組,觸發(fā)該事件
                     if(this.onshow){
                            for(var i=0;i<this.onshow.length;i++){
                                  this.onshow[i](); //調(diào)用事件處理程序
                            }
                     }
                },
                attachOnShow:function(_eHandler){
                      if(!this.onshow)this.onshow=[]; //用數(shù)組存儲(chǔ)綁定的事件處理程序引用
                      this.onshow.push(_eHandler);
                }
          }
          var obj=new class1();
          //事件處理程序1
          function onShow1(){
                alert(1);
          }
          //事件處理程序2
          function onShow2(){
                alert(2);
          }
          //綁定兩個(gè)事件處理程序
          obj.attachOnShow(onShow1);
          obj.attachOnShow(onShow2);
          //調(diào)用show,觸發(fā)onshow事件
          obj.show();
          //-->
          </script>
          從代碼的執(zhí)行結(jié)果可以看到,綁定的兩個(gè)事件處理程序都得到了正確的運(yùn)行。如果要綁定有參數(shù)的事件處理程序,只需加上createFunction方法即可,在上一節(jié)有過描述。
          這種機(jī)制基本上說明了處理多事件處理程序的基本思想,但還有改進(jìn)的余地。例如如果類有多個(gè)事件,可以定義一個(gè)類似于attachEvent的方法,用于統(tǒng)一處理事件綁定。在添加了事件綁定后如果想刪除,還可以定義一個(gè)detachEvent方法用于取消綁定。這些實(shí)現(xiàn)的基本思想都是對(duì)數(shù)組的操作。

          posted on 2007-10-09 09:41 lk 閱讀(265) 評(píng)論(0)  編輯  收藏 所屬分類: ajax&js
          主站蜘蛛池模板: 景谷| 宝应县| 晋江市| 池州市| 龙海市| 博乐市| 丹寨县| 休宁县| 长寿区| 泊头市| 连州市| 台东县| 如东县| 滕州市| 桂平市| 临湘市| 聂拉木县| 南和县| 静乐县| 调兵山市| 方正县| 海原县| 蓝田县| 开远市| 深水埗区| 西畴县| 扶绥县| 绥芬河市| 贵德县| 资中县| 萝北县| 永善县| 靖安县| 任丘市| 金溪县| 临潭县| 石城县| 沅陵县| 临漳县| 黄冈市| 谢通门县|