zoukankan      html  css  js  c++  java
  • DOJO试用手记2Event System【原创】

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

  • 相关阅读:
    作业一:计算机是如何工作的进行
    信息安全系统设计基础期末总结
    信息安全设计基础系统第十四周学习总结
    信息安全设计基础系统第十三周学习总结
    信息安全系统设计基础_exp3
    信息安全系统设计基础第十二周学习总结
    信息安全系统设计基础第十一周
    信息安全系统设计基础_exp2
    信息安全系统设计基础第十周学习总结
    信息安全系统设计基础_exp1
  • 原文地址:https://www.cnblogs.com/zxub/p/364756.html
Copyright © 2011-2022 走看看