贏在執行

          這個世界上只有兩樣東西愈分享愈多,那就是智慧與愛。

          BlogJava 首頁 新隨筆 聯系 聚合 管理
            17 Posts :: 11 Stories :: 13 Comments :: 0 Trackbacks
          DOJO試用手記2--Event System
          來源:原創 作者:zxub 發布時間:2006-04-02 11:13:00  

            首先接觸到的,是dojo的Event System。
            以前,我們是由頁面控件觸發一系列時間的時候,整個事件鏈要先定義好,然后才能按需要調用已經寫好的調用模塊,一旦要修改事件鏈,就不是那么容易了。由一個函數調用另一個函數,能隨便說要調用哪個嗎?能在運行的時候很容易修改嗎?除了那些大師級的人物,我相信我們這些菜鳥要解決這些問題,要費不少事。
            在dojo中,其關注的事件不僅僅是Dom事件,它把任何的js方法調用都看作可以偵聽的事件,這就把一切都統一到一個地方了。
            我們都寫過這樣的代碼:

          1 var buttonNode= document.getElementById("button");
          2 function foo()
          3 {
          4     alert("foo");
          5 }
          6 buttonNode.onclick = function()
          7 {
          8     foo();
          9 }

            
            要調用foo函數,需要這么寫,如果說接著我還要調用一個函數呢?那么,就需要重寫buttonNode的onclick事件函數,把以前的都再寫一遍,如果我還要再調用呢。。。。
             我們來看看dojo中是怎么解決的,看下面的一句

          1 dojo.event.connect(buttonNode,"onclick","foo");

            就這么一句,就綁定了觸發函數,想再加?那就繼續用dojo.event.connect(buttonNode,"onclick","foo2")...
            還有這么一種寫法:

          dojo.event.connect(handlerNode, "onclick"function(evt){
              
          // 
          });

            上面是buttonNode綁定一個函數,如果要與某對象的某個函數綁定的話,就用

          dojo.event.connect(buttonNode, "onclick", object, "handler");

            object是目標對象,handler是目標對象的函數,這里要注意,object不僅僅是頁面控件,一切對象皆可行,就又回到“關注的事件不僅僅是Dom事件,它把任何的js方法調用都看作可以偵聽的事件”。要解除綁定的話,就可以使用dojo的disconnect方法,調用參數一定要與connect一致,即可解除之前的綁定操作。
            dojo中connect函數的參數有下面幾種:
          • object, name, name
          • object, name, function pointer
          • object, name, object, name
            再看看這段:

           1 var exampleObj = {
           2     counter: 0,
           3     foo: function(){ 
           4         alert("foo");
           5         this.counter++;
           6     },
           7     bar: function(){
           8         alert("bar");
           9         this.counter++;
          10     }
          11 };
          12 
          13 dojo.event.connect(exampleObj, "foo", exampleObj, "bar");
          14 
          15 

            最后一句的作用是什么?使得執行exampleObj的foo函數之后,執行exampleObj的bar函數,一切對象皆可綁定!
            為了防止不經意間對事件的多處綁定,造成連鎖調用。Dojo提供關鍵字鏈綁定,比如可以只綁定一次:

          1 dojo.event.kwConnect({
          2   srcObj: exampleObj,
          3   srcFunc: "foo",
          4   targetObj: exampleObj,
          5   targetFunc: "bar",
          6   once: true
          7 });

            同樣,對應也提供了一個kwDisconnect()方法來進行關鍵字綁定的解除。
            在connect()和KwConnect()中,可以實現延遲執行和循環執行。
            KwConnect()中,只需要加一個delay屬性就可以了,測試代碼如下:
           1 <HTML>
           2 <HEAD>
           3 <TITLE> New Document </TITLE>
           4 <META NAME="Generator" CONTENT="EditPlus">
           5 <META NAME="Author" CONTENT="">
           6 <META NAME="Keywords" CONTENT="">
           7 <META NAME="Description" CONTENT="">
           8 <script type="text/javascript" src="dojo.js"></script>
           9 
          10 </HEAD>
          11 
          12 <BODY>
          13 <INPUT TYPE="button" id="eee" value="test">
          14 <script language="javascript">
          15 
          16 var exampleObj = {
          17     counter: 0,
          18     foo: function(){ 
          19         alert("foo");
          20         this.counter++;
          21     },
          22     bar: function(){
          23         alert("bar");
          24         this.counter++;
          25     }
          26 };
          27 
          28 dojo.event.kwConnect({
          29   srcObj: exampleObj,
          30   srcFunc: "foo",
          31   targetObj: exampleObj,
          32   targetFunc: "bar",
          33   delay: 3000
          34 });
          35 dojo.event.connect(document.getElementById("eee"),"onclick",exampleObj,"foo");
          36 
          37 
          38 </script>
          39 </BODY>
          40 </HTML>

            由上面的延遲,可以想到,如果目標等于源的話,那么就是一個循環執行!
            據說在connect()中,延遲信息在它的第九個參數,具體怎么樣,我還沒去試。
            上面是在事件發生后調用目標,如果要在發生前呢?就是下面的東西了:

          dojo.event.connect("before", exampleObj, "foo", exampleObj, "bar");

            很容易理解吧,我就不多說了。在KwConnect中,就是

          dojo.event.kwConnect({
              type:       
          "before"
              srcObj:     exampleObj, 
              srcFunc:    
          "foo"
              targetObj:  exampleObj,
              targetFunc: 
          "bar"
          });

            默認情況下,connect()中第一個參數就是"after"了,同理KwConnect中的type默認是"after"。
            下面要說的是方法包裝。當我們想改變方法的輸入輸出時,一般情況下是直接去修改代碼,那么,如果不修改原方法怎么辦呢?在dojo中,也給出了解決方法,就是用Around advice包裝方法。下面是一個例子:

          <HEAD>
          <TITLE> New Document </TITLE>
          <script type="text/javascript" src="dojo.js"></script>

          </HEAD>

          <BODY>
          <INPUT TYPE="button" id="eee" value="test">
          <script language="javascript">
          function foo(arg1, arg2)
          {
             
          return arg1+arg2;
          }
          function aroundFoo(invocation){
            
          if(invocation.args.length < 2){    
              invocation.args.push(
          3);
            }
            
          var result = invocation.proceed(); 
            
          //result="sss";
            return result;
          }
          dojo.event.connect(
          "around""foo""aroundFoo");
          dojo.event.connect(document.getElementById(
          "eee"),"onclick",function(){alert(foo(1))});
          </script>
          </BODY>
          </HTML>

            結果是4,如果取消注釋,則結果為"sss",開始調用的時候,只傳了個參數1,經過包裝處理,添加了一個默認參數,然后繼續,函數執行完畢后,還可以將輸出結果再處理一遍,當然,只是在函數有返回值的時候。
            這里要注意的是:函數aroundFoo有且只能有一個參數,就是要改變的方法對象。這樣,每次執行foo函數時,都會進行包裝,然后再輸出。
            利用connect()的時候,有一個問題就是參數傳遞,參數不一致,該怎么辦?先看下面一段:
           1 <HTML>
           2 <HEAD>
           3 <TITLE> New Document </TITLE>
           4 <script type="text/javascript" src="dojo.js"></script>
           5 </HEAD><BODY>
           6 <script language="javascript">
           7 var obj1 = {
           8     twoArgFunc: function(arg1, arg2){
           9         alert("1:"+arg1+" "+arg2);
          10     }
          11 };
          12 
          13 var obj2 = {
          14     oneArgFunc: function(arg1,arg2){
          15         alert("2:"+arg1+" "+arg2);
          16     }
          17 };
          18 
          19 dojo.event.connect(obj1, "twoArgFunc"
          20                     obj2, "oneArgFunc");
          21 
          22 obj1.twoArgFunc(1,4);
          23 </script>
          24 </BODY>
          25 </HTML>


            結果是怎樣的呢?2個連接的函數的參數相同!所以,要傳遞參數到另外一個函數中,已經不需要我們多做什么,dojo已經傳過去了,參數的格式不一致的話,我們只需要再包裝一下目標函數。
            網上的那個例子我怎么也調試不成功,花了點時間,改了下,終于好了,下面是代碼:

           1 <HTML>
           2 <HEAD>
           3 <TITLE> New Document </TITLE>
           4 <script type="text/javascript" src="dojo.js"></script>
           5 
           6 </HEAD>
           7 
           8 <BODY>
           9 <script language="javascript">
          10 var obj1 = {
          11     twoArgFunc: function(arg1, arg2){
          12         // 需要2個參數
          13         alert("1: "+arg1+" "+arg2);
          14     }
          15 };
          16 
          17 var obj2 = {
          18     oneArgFunc: function(arg1){
          19         //只需要一個數組作為參數
          20         alert("2: "+arg1);        
          21     }
          22 };
          23 
          24 function aroundFunc(invocation){
          25     var tmpArgs = [ 
          26                     invocation.args[0],
          27                     invocation.args[1]
          28                   ];
          29     invocation.args = [tmpArgs];
          30     return invocation.proceed();
          31 }
          32 
          33 // after-around advice
          34 dojo.event.connect("after",obj1, "twoArgFunc",obj2, "oneArgFunc","aroundFunc");
          35 
          36 //也可以寫成下面2句
          37 //dojo.event.connect(obj1, "twoArgFunc",obj2, "oneArgFunc");
          38 //dojo.event.connect("around",obj2,"oneArgFunc","aroundFunc");
          39 
          40 obj1.twoArgFunc(1,4);
          41 </script>
          42 </BODY>
          43 </HTML>
          44 


            要注意的是,34行的after不能少,少了就觸發不了了,照道理默認就是after的啊,具體可能是dojo內部問題吧。
             接下來介紹匿名通信。
            對象之間,不可能總是互相可見的,可能要連接的對象不是同時產生的,也就是說,異步產生,這樣的話,用connect()就不是那么方便了,什么時候connect(),就是個問題了。dojo中,"Topics to the rescue!",dojo是利用topic機制來解決的。看下面的代碼

           1 var exampleObj = {
           2     counter: 0,
           3     foo: function(){ 
           4         alert("foo");
           5         this.counter++;
           6     },
           7     bar: function(){
           8         alert("bar");
           9         this.counter++;
          10     }
          11 };
          12 
          13 // previously we used this connect syntax
          14 //
          15 //  dojo.event.connect(exampleObj, "foo", exampleObj, "bar");
          16 //
          17 // which we now replace with:
          18 
          19 // set up our publisher
          20 dojo.event.topic.registerPublisher("/example", exampleObj, "foo");
          21 
          22 // and at some point later, register our listener
          23 dojo.event.topic.subscribe("/example", exampleObj, "bar");
          24 
          25 


            由上面可以看到,連接是分步進行的。在前面說明,要連接一個對象,具體是哪個,它可以不用知道,后面,可以指定一個連接對象,這樣,2個連接的對象,不知道對方是誰,因為它們是通過發布/訂閱機制通信,是通過中轉的。這么做有什么好處?不用我說了吧。這就是匿名通信。

          posted on 2007-10-18 00:28 飛雪(leo) 閱讀(258) 評論(0)  編輯  收藏 所屬分類: DOJO
          主站蜘蛛池模板: 郯城县| 香格里拉县| 保亭| 垫江县| 石家庄市| 都兰县| 靖江市| 什邡市| 临猗县| 个旧市| 凌源市| 根河市| 抚顺市| 曲沃县| 三江| 梅河口市| 鹤岗市| 临漳县| 伽师县| 巴楚县| 弥勒县| 项城市| 柘荣县| 二手房| 金昌市| 桓台县| 西城区| 资兴市| 邹平县| 新巴尔虎左旗| 嘉鱼县| 东乡县| 伊宁市| 普宁市| 明星| 盐城市| 沈丘县| 清新县| 松潘县| 同德县| 和田县|