DOJO试用手记2--Event System

DOJO试用手记2--Event System
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个连接的对象,不知道对方是谁,因为它们是通过发布/订阅机制通信,是通过中转的。这么做有什么好处?不用我说了吧。这就是匿名通信。

你可能感兴趣的:(DOJO试用手记2--Event System)