`
xiaotian_ls
  • 浏览: 304397 次
  • 性别: Icon_minigender_1
  • 来自: 济南
社区版块
存档分类
最新评论

Dojo 事件机制

    博客分类:
  • Ajax
阅读更多
事件是用户与站点进行交互的基础。现在的浏览器采用的事件处理方法千差万别,为了屏蔽这些差异,Dojo 提供了统一的事件处理方法。开发人员可以使用 Dojo 的简单连接或者订阅/发布模式来进行事件处理,本系列 的这一期文章将对这些知识进行一一介绍。
<!----><!----><!---->

DOM 事件模型

事件是用户与浏览器交互的基础,用户在界面的操作产生事件,浏览器捕获事件后对用户作出反馈。 Ajax 技术通过引入异步调用使 web 应用的开发产生了革命性的变化,另一方面 Ajax 也使广大开发人员认识到用户和浏览器的交互可以如此精彩,Web 页面不再死板,开始鲜活起来,开发人员也不再厌恶编写 javascript 的事件处理代码。在 web 页面中,事件一般作用于 DOM 树节点,所以有必要先了解 DOM 的事件模型,包括模型支持那些事件,如何处理 DOM 树结构上的节点的事件等。


清单 1

				
 <html> 
 <body> 
 <script> 
 function sayHello() { alert("hello!"); } 
 </script> 
 <input id="btn" type="button" onclick="sayHello()" value="hello" /> 
 </body> 
 </html>

清单 1 应该是最为 web 开发人员熟知的事件处理方式了,直接把事件处理函数和控件上的事件属性绑定起来。当用户点击 hello 按钮时,将调用 sayHello() 函数。当然也可以把事件处理函数的代码作为 onclick 的值,参见清单 2,使用这种方式时,onclick 对应的处理脚本应比较简单短小,在 onclick 后面写上一大串 javascript 脚本可不是什么好主意。


清单 2

				
 <html> 
 <body> 
 <input id="btn" type="button" onclick="javascript:alert('hello');" value="hello" /> 
 </body> 
 </html>

另一种略微高级的方法是在控件之外绑定控件的事件处理函数,见清单 3 。


清单 3

				
 <html> 
 <body> 
 <input id="btn" type="button"  value="hello" /> 
 <script> 
 document.getElementById("btn").onclick=sayHello; 
 function sayHello() { alert('Hello'); } 
 </script> 
 </body> 
 </html>

在清单 3 的例子中,首先通过 document.getElementById 获取需要绑定事件的控件,再把控件的 onclick 事件设置为事件处理函数,其效果与前面的例子是一样的。需要注意的是,script 脚本放到了控件后面,因为使用了 document.getElementById 去获控件,而 javascript 是解释执行的,必须保证控件在执行到 getElementById 之前已经创建了,否则会出现找不到控件的错误。但 sayHello 为什么会在事件绑定语句的后面呢?按照刚才的原则,不是必须确保 sayHello 已经预先定义好了吗?其实不然,事件处理函数的代码直到事件发生时才被调用,此时才会检查变量是否已经定义,函数是否存在,而页面初次加载时按钮上的 click 事件是不会发生的。页面加载后用户再点击按钮,sayHello 函数已经完全加载到页面中,函数是存在的。当然如果是普通的函数调用,一定要保证被调用函数出现在调用函数之前。采用清单 3 所示的这种方式时,在 web 应用比较复杂时,可以把事件处理函数集中放在一起,比如单独存放在一个文件中,方便以后查找,修改。这个例子也很好的说明了 javascript 是一种解释执行的脚本语言。

前面三种事件处理方式是在 W3C DOM Level0 中定义的,是不是简单易用?但是似乎太简单了,缺少一些东西。首先一个事件只能绑定一个处理函数,不支持多个事件处理函数的绑定。如果开发人员被迫把事件处理代码都放在一个函数中,代码的模块性会很差。其次解除事件处理函数的绑定的方式很不友好,只能把它设为空值或者空串。

 document.getElementById("btn").onclick=null; 
 document.getElementById("btn").onclick="";

W3C DOM Level2 标准有了新的事件模型,新模型最大的变化有两点:

首先,事件不再只传播到目标节点,事件的传播被分为三个阶段:捕获阶段,目标节点阶段,冒泡阶段。一个事件将在 DOM 树中传递两次,首先从 DOM 根节点到目标节点(捕获阶段),然后从目标节点传递到根节点(冒泡阶段)。在这三个阶段都可以捕获事件进行处理,也可以阻止事件继续传播。 W3C 的官方网站有关于这三个阶段的详细说明。在 DOM Level0 定义的事件模型中,事件只能被目标节点处理,其实这也是大部分支持事件处理的编程语言采用的机制,比如 Java,C# 。但是这种方式可能并不适合结构比较复杂的 web 页面。比如很多链接都需要自定义的 tooltip,在 DOM Level0 的方式下,需要给每个链接的 mouseover,mouseout 事件提供事件处理函数,工作量很大。而在 DOM Level2 模型中,我们可以在这些链接的公共父节点上处理 mouseover,mouseout 事件,在 mouseover 时显示一个 tooltip,mouseout 时隐藏这个 tooltip 。这样只需要对一处进行更改即可给每个链接添加上自定义的 tooltip 。所以 DOM Level2 的设计者定义出分为三个阶段的事件模型也是为了适应复杂的 web 页面,让开发人员在处理事件上有更大的自由度。

其次,支持一个事件注册多个事件处理函数,也能够删除掉这些注册的事件处理函数。一个事件可以注册多个事件处理函数同样是大部分的编程语言的事件处理机制支持的方式。这种方式在面向对象的开发中尤为重要,因为可能很多对象都需要监听某一事件,有了这种方式,这些对象可以随时为这一事件注册一个事件处理函数,事件处理函数的注册是分散的,而不像在 DOM Level0 中,事件处理是集中式的,使用这种方式使得事件的“影响力”大大增强。


清单 4

				
 <html> 
 <body> 
 <input id="btn" type="button"  value="hello" /><p /> 
 <input id="rme" type="button"  value="remove" /> 
 <script> 
 function sayHello(event) { alert("hello"); }; 
 function sayWorld(event) { alert("world"); }; 
 function remove() { 
	 btn.removeEventListener("click", sayHello, false); 
	 btn.removeEventListener("click", sayWorld, false); 
 } 
 var btn = document.getElementById('btn'); 
 btn.addEventListener("click", sayHello, false); 
 btn.addEventListener("click", sayWorld, false); 
 document.getElementById('rme').addEventListener("click", remove, false); 
 </script> 
 </body> 
 </html>

清单 4 是使用 DOM Level2 定义的事件模型的例子,在这个例子中,首先为 hello 按钮的 click 事件注册了两个事件处理函数,分别用来显示“ hello ”和“ world ”警示框。然后为 remove 按钮的 click 事件处理了一个事件处理函数,用来删除注册在 hello 按钮上的事件处理函数。例子很简单,但是足够说明 DOM Level2 中的事件处理机制。

  • addEvenetListener(/*String*/eventName, /*function*/handler, /*bool*/useCapture)

    为某一 HTML 元素注册事件处理函数,eventName:该元素上发生的事件名; handler:要注册的事件处理函数,useCapture:是否在捕获阶段调用此事件处理函数,一般为 false,即只在事件的冒泡阶段调用这一事件处理函数。

  • reomveEvenetListener(/*String*/eventName, /*function*/handler, /*bool*/useCapture);

    删除某一 HTML 元素上注册的事件处理函数,函数声明与 addEventListener 一样,参数意义也相同,即注册、删除事件处理函数时也需要使用同样的参数。这点不太方便,比较好的做法是 addEventListener 返回一个句柄,然后把这个句柄传递作为 removeEventListener 的参数。

sayHello, sayWorld 是两个事件处理函数,他们的参数 event 是一个事件对象,对象的属性包括事件类型(在本例中是 click),事件发生的 X,Y 坐标(这两个属性在实现 tooltip 时特别有用),事件目标(即事件的最终接收节点)等。

从这个例子中也可以看出事件处理包括三个方面:事件源、事件对象、事件处理函数。事件处理机制就是把这三个方面有机的联系起来。

注意,清单 4 的例子不能运行在 IE 浏览器里,因为 IE 浏览器采用是一种介乎 DOM level0 和 DOM Level2 之间的事件模型。比如在 IE 中,应该使用 attachEvent(), detachEvent() 来注册、注销事件处理函数。这只是 IE 中的事件模型与标准 DOM Level2 事件模型不一致部分的冰山一角,其他的诸如事件对象的传播方式、事件对象的属性、阻止事件传播的函数等,IE 与 DOM Level2 都有很大差异。这也是为什么 Dojo 会再提供一些事件处理的 API 的原因:屏蔽底层浏览器的差异,让开发人员在写编写事件处理代码时面对的是“透明”的浏览器,即不需要关心浏览器是什么。前面花了很大篇幅来介绍 DOM 事件模型,因为 Dojo 的事件处理机制是基于 DOM Level2 定义的事件模型的,然后对浏览器不兼容的情况做了很多处理,以保证使用 Dojo 的事件处理机制编写的代码能在各个浏览器上运行。下面来介绍 Dojo 的事件处理机制。

使用 Dojo 处理 DOM 事件

当 Dojo 运行在支持 DOM Level2 事件模型的浏览器中时,Dojo 只是把事件处理委托给浏览器来完成。而在与 DOM Level2 的事件模型不兼容的浏览器(比如 IE)中,Dojo 会尽量使用浏览器的 API 模拟 DOM Level2 中的事件处理函数。 Dojo 最终提供给开发者一个称为“简单连接”的事件处理机制来处理 DOM 事件。

为什么叫“简单连接”呢,因为绑定事件处理函数的函数名叫 dojo.connect,相应的注销的函数是 dojo.disconnect 。

  • dojo.connect = function(/*Object|null*/ obj, /*String*/ event, /*Object|null*/ context, /*String|Function*/ method, /*Boolean*/ dontFix)

    参数 obj 事件源对象,比如 DOM 树中的某一节点; event 参数表示要连接的事件名,如果是 dojo.global(在浏览器中一般是 window 对象)域上的事件,则 obj 参数可以置为 null,或者不写。 context 指事件处理函数所在的域(比如一个对象); method 表示事件处理函数名,如果是全局函数,则 context 参数可置为 null,或者不写这个参数; dontFix 表示不需要处理浏览器兼容的问题,默认为 false ;如果你的应用只在支持 DOM Level2 事件模型的浏览器上运行,则可以把它设为 true,但是这种几率太小了,因为 IE 就不是完全支持 DOM Level2 事件模型。 dojo.connect 函数可以返回一个 handle,在 dojo.disconnect 中会用到。

  • dojo.disconnect = function(/*Handle*/ handle)

    dojo.disconnect 函数用来注销已注册的事件处理函数,参数是一个 dojo.connect 时返回的 handle 。

下面来看看如何使用 Dojo 的简单连接机制处理 DOM 事件。


清单 5

				
 <html> 
 <head> 
 <script type="text/javascript" 
 djConfig="parseOnLoad: true, isDebug: true" 
 src="../dojo/dojo/dojo.js"></script> 
 </head><body><script> 
 function $(id) { return document.getElementById(id); } 
 function handler(eventObj) { 
	 console.info("eventType=" + eventObj.type + "; node=" 
			 + eventObj.target.id + "; currentTarget=" 
			 + eventObj.currentTarget.id); 
	 //if Shift Key pressed 
	 if (eventObj.shiftKey) { 
		 //stop bubbling 
		 eventObj.stopPropagation(); 
	 } 
 } 
 function handler2(eventObj) { console.info("this is for test"); } 
 function connect() { 
	 dojo.connect($("book"), "click" , handler); 
	 dojo.connect($("cpp"), "click" , handler); 
	 dojo.connect($("b1"), "mouseover" , handler); 
	 dojo.connect($("b1"), "mousedown" , handler); 
	 dojo.connect($("b1"), "click" , handler); 
	 dojo.connect($("b2"), "click" , handler); 
	 dojo.connect($("b2"), "click" , handler2); 
	 dojo.connect($("b3"), "click" , handler); 
 } 
 dojo.addOnLoad(connect); 
 </script> 
 <div id="book"> 
	 <ol id="cpp"> 
		 <li id="b1">C++ primer</li> 
		 <li id="b2">Thinking in C++</li> 
		 <li id="b3">Inside C++ object model</li> 
	 </ol> 
 </div> 
 </body> 
 </html>

清单 5 的页面中有一个跟 c++ 相关的书的列表,列表的每一项都通过 dojo.connect 绑定了一个或多个事件处理函数。第一项“ c++ primer ”给 mouseover,mousedown,click 三个事件注册了事件处理函数,第二项“ Thinking in c++ ”注册了两个 click 事件处理函数 handler 和 handler2,第三项“ Inside C++ object model ”绑定了 click 事件。这个例子可以说包括了“简单连接”机制的方方面面。

首先来看看 dojo.connect 的使用,dojo.connect 能够把多个事件处理函数绑定在一个事件上,第二项“ Thinking in c++ ”的 click 事件就绑定了两个事件处理函数。在本例中,并没有给 dojo.connect 函数传递事件处理函数的 context,因为默认的是 dojo.global,而两个事件处理函数 hander 和 hander2 都是全局函数,所以不需要显示传递 dojo.global 。

再来看事件处理函数 handler 和 handler2 。 handler2 只是用来说明 dojo.connect 可以绑定多个事件处理函数,不多说; handler 是主要的事件处理函数,在 handler 里先输出了事件对象的三个属性,type、target、currentTarget,type 表示事件的类型,target 表示事件目标节点,currentTarget 表示当前事件传递到哪个节点了,输出他们三个是为了说明 Dojo 也是在冒泡阶段处理事件的(还记得在 DOM 事件模型部分对事件的三个阶段的描述吗?)。所以当点击第三项 b3 时,在浏览器的模拟控制台输出是

 eventType=click; node=b3; currentTarget=b3 
 eventType=click; node=b3; currentTarget=cpp 
 eventType=click; node=b3; currentTarget=book

可以看出,首先会触发 b3 的事件处理函数,然后是 id 为 cpp 的 ol 元素的 click 事件处理函数,最后是 id 为 book 的 div 。所以毫无疑问 Dojo 是在事件的冒泡阶段处理事件的,capture 阶段并不做任何处理。 handler 的最后是关于阻止事件传播的代码,如果按住 shift 键,再点击第三项时,只会在模拟控制台输出:

eventType=click; node=b3; currentTarget=b3

后面两个事件没有发生,因为 click 事件被 stopPropagation 阻止了,没有再往上冒。事实上,可以在任何一级对象上调用 stopPropagation 阻止事件继续往上传递。

然后是事件对象 eventObj,事件对象是对事件的描述,在前面已经介绍了事件对象的几个有用的属性。 Dojo 的事件对象其实基于 DOM Level2 的事件对象,更详细的属性信息可以参考 Dojo 的官方文档,这里对用户操作触发的事件和事件的继承结构做些说明。当用户点击第一项 b1 时,在浏览器输出的是

eventType=mouseover; node=b1; currentTarget=b1
eventType=mousedown; node=b1; currentTarget=b1
eventType=click; node=b1; currentTarget=b1
eventType=click; node=b1; currentTarget=cpp 
eventType=click; node=b1; currentTarget=book

从上面的输出可以看出,在 b1 这个节点上一共监测到了三个事件(事实上产生的事件不止三个),mouseover、 mousedown、click 。所以表面上一个点击操作背后却藏着大文章。同理用户点击提交按钮提交一个表单也会触发很多事件,但一般我们只处理了最上层的 submit 事件。这些现象揭示了事件是有类别,层次的,底层事件可以触发高层事件。底层事件一般都是与设备有关的事件,比如鼠标移动,按键产生的事件;高层事件一般指页面元素上的事件,比如链接的 click 事件,表单的 submit 事件等。与设备无关的事件往往由几个与设备有关的事件触发。比如一个单击页面上按钮的 click 事件,可以分解为 mouseover, mousedown, mouseup 三个事件,在这三个事件发生之后,将触发按钮的 click 事件。开发人员应该了解这些知识,因为它有助于写出高效的事件处理程序。

最后是事件目标,在 W3C DOM Level2 的事件模型里,事件目标不仅仅是 DOM 树种最底层的接收事件的节点,它可以是从这个底节点到跟节点路径上的任何一个节点。

Dojo 目前支持的事件类别包括 UIEvent,HTMLEvent, MouseEvent,每类事件具有的属性并不一样,比如只能在 MouseEvent 里才能获得事件发生时鼠标的位置等。

使用 Dojo 处理用户自定义事件

既然 W3C 已经定义了标准的 DOM Level2 事件模型,为什么 Dojo 还要提供 connect 函数来注册事件处理函数呢,为何不使用 DOM Level2 的 addEventListener 函数?从前面的叙述中也看不出 connect 与 addEventListener 有明显的不同之处。确实在处理 DOM 事件上,Dojo 的 connect 与 addEventListener 无甚大的不同,但是 Dojo 的 connect 函数还可以处理用户自定义事件。这是 addEventListener 所不具备的。下面来看看怎么使用 dojo.connect 来处理用户自定义事件。

用户自定义事件是指用户指定的函数被调用时触发的“事件”,当指定函数被调用时,将促发监听函数被调用。有点类似于 AOP 的编程思想,但在 Javascript 中实现 AOP 比起面向对象的编程语言要简单得多。


清单 6

				
 <html> 
 <head> 
 <script type="text/javascript" 
 djConfig="parseOnLoad: true, isDebug: true" 
 src="../dojo/dojo/dojo.js"></script> 
 </head> 
 <body> 
 <script type="text/javascript"> 
 function print(fName, args) { 
	 var message = "In " + fName + "; the arguments are: " 
	 dojo.forEach(args, function(args) { 
		 message += args.toString() + " "; 
	 }) ; 
	 console.log(message); 
 } 
 function handler1() { print("handler1", arguments); } 
 function handler2(a1, a2) { print("handler2", [a1, a2]); } 
 function userFunction() { 
	 print("userFunction", arguments); 
 } 
 dojo.connect("userFunction", null, "handler1"); 
 dojo.connect("userFunction", null, "handler2"); 
 userFunction(1, 2); 
 </script> 
 </body> 
 </html>

运行清单 6 的例子,会在页面中的一个模拟控制台中输出:

In userFunction; the arguments are: 1 2 
 In handler1; the arguments are: 1 2 
 In handler2; the arguments are: 1 2

调用 userFunction 时,handler1 和 handler2 也被触发了。 userFunction 就像是一个事件源,它的调用像一个事件,而 handler1 和 hander2 就是事件处理函数。那么这种情况下,事件对象又在哪呢? handler1 事件处理函数没有显式的参数,通过在控制台的输出可以得知它实际上有两个参数,值分别为 1 和 2 ; handler2 有两个显式参数,值也为 1 和 2 。所以 Dojo 只是把 userFunction 的两个参数传递给了事件处理函数,不像在处理 DOM 事件时,提供一个封装好的事件对象。在本例中 userFunction 只“连接”了两个函数,很显然它还可以连接更多的事件处理函数,这些事件将按连接的先后顺序来执行。

Dojo 的订阅/发布模式

dojo.connect 函数用来处理某一个实体上发生的事件,不管处理的是 DOM 事件还是用户自定义事件,事件源和事件处理函数是通过 dojo.connect 直接绑定在一起的,Dojo 提供的另一种事件处理模式使得事件源和事件处理函数并不直接关联,这就是“订阅/发布”。“订阅/发布”模式可以说是一个预订系统,用户先预定自己感兴趣的主题,当此类主题发布时,将在第一时间得到通知。这跟我们熟知的网上购物系统不一样,网上购物是先有物,用户再去买,而在订阅/发布模式下,预订的时候并不确定此类主题是否已存在,以后是否会发布。只是在主题发布之后,会立即得到通知。订阅/发布模式是靠主题把事件和事件处理函数联系起来的。在 Dojo 中,跟主题订阅 / 发布有关的函数有三个:

  • dojo.subscribe = function(/*String*/ topic, /*Object|null*/ context, /*String|Function*/ method)

    subscribe 函数用来订阅某一主题;参数 topic 表示主题名字,是一个字符串; context 是接收到主题后调用的事件处理函数所在的对象,function 是事件处理函数名。

  • dojo.unsubscribe = function(/*Handle*/ handle)

    取消对于某一主题的订阅;参数 handle 是 dojo.subscribe 返回的句柄,跟 dojo.connect 与 dojo.disconnect 的工作方式一样。

  • dojo.publish = function(/*String*/ topic, /*Array*/ args)

    发布某一主题;参数 topic 是主题的名字,args 表示要传递给主题处理函数的参数,它是一个数组,可以通过它传递多个参数给事件处理函数。

订阅 / 发布模式看上去很神秘,但实现是比较简单的。 dojo 维护了一个主题列表,用户订阅某一主题时,即把此主题及其处理函数添加到主题列表中。当有此类主题发布时,跟这一主题相关的处理函数会被顺序调用。注意:如果用户使用了相同的处理函数重复订阅某一主题两次,在主题列表中这是不同的两项,只是他们都对同一主题感兴趣。当此类主题发布时,这两个处理函数都会被调用,而不会出现第二个处理函数覆盖第一个处理函数的状况。清单 7 的例子展示了订阅 / 发布模式是如何工作的。


清单 7

				
 <html> 
 <head> 
 <script type="text/javascript" 
 djConfig="parseOnLoad: true, isDebug: true" 
 src="../dojo/dojo/dojo.js"></script> 
 </head> 
 <body> 
 <script> 
 var NewsReporter = { 
	 sports : function(message) { 
		 for (var i = 0; i < message.length; i++) 
			 console.info("sports:" + message[i]); 
	 }, 
	 entertainment: function(message) { 
		 for (var i = 0; i < message.length; i++) 
			 console.info("entertainment:" + message[i]); 
	 } , 
	 mixed: function (sportsNews, entermaintainNews) { 
		 console.info("mixed"); 
		 this.sports(sportsNews); 
		 this.entertainment(entermaintainNews); 
	 } 
 } 
 /*first subscribe*/ 
 handle1 = dojo.subscribe("sports news", NewsReporter, "sports"); 
 dojo.publish("sports news", 
   [["China will rank first in the 29th Olympic"]]); 

 handle2 = dojo.subscribe("sports news", NewsReporter, "sports"); 

 dojo.subscribe("entertainment news", NewsReporter, "entertainment"); 
 dojo.subscribe("mixed news", NewsReporter, "mixed"); 
 /*then publish*/ 
 dojo.publish("sports news", 
   [["America will rank second in the 29th Olympic", 
   "Russia will third forth in the 29th Olympic"]]); 
 dojo.publish("entertainment news", 
   [["Red Cliff earns over 200 million in its first week"]]); 
 dojo.publish("mixed news", 
   [["Yao Ming gives Red Cliff high comments"], 
   ["Jay and S.H.E wish Beijing Olympic success"]]); 

 //unsubscribe two sports news reporter 
 dojo.unsubscribe(handle1); 
 dojo.unsubscribe(handle2); 
 dojo.publish("sports news", 
   [["this news has no consumer!"]]); 
 </script> 
 </body> 
 </html>

在清单 7 的例子中,模拟了一个“新闻记者”(NewsReporter 对象),专门跑体育和娱乐新闻,任何此类新闻他都不会放过。 Dojo 就像一个新闻中心,发布各类新闻。

记者先在新闻中心注册,说自己对体育新闻感兴趣,接着新闻中心发布了一条新闻“ China will rank first in the 29th Olympic ”,这时新闻记者将立即收到这条消息,并报道出来(在本例中就是在浏览器的模拟控制台输出这条新闻)。然后记者又再次向新闻中心注册对体育和娱乐新闻以及跨这两个领域的新闻都感兴趣,然后新闻中心分别发布了这三个主题的新闻。记者当然不敢懈怠又马上输出了这些新闻,最后新闻记者不打算再跑体育新闻了,就在新闻中心取消了对体育新闻的注册。这个例子最终将在浏览器的模拟控制台输出:

 sports:China will rank first in the 29th Olympic 
 sports:America will rank second in the 29th Olympic 
 sports:Russia will third forth in the 29th Olympic 
 sports:America will rank second in the 29th Olympic 
 sports:Russia will third forth in the 29th Olympic 
 entertainment:Red Cliff earns over 200 million in its first week 
 mixed 
 sports: Yao Ming gives Red Cliff high comments 
 entertainment: Jay and S.H.E wish Beijing Olympic success

从这个例子中我们可以得到几个使用订阅/发布模式时的注意事项。

  1. 先订阅,再发布。主题发布的时候,订阅了这一主题的事件处理函数会被立即调用。
  2. 发布函数的参数为数组,发布第一条新闻时使用的是

    [["China will rank first in the 29th Olympic"]],这是一个二维数组,因为事件处理函数 NewsReporter.sports,NewsReporter.entertainment,以及 NewsReporter.mixed 的参数已经是一个数组,所以在发布时必须把新闻事件这个数组再放在另一个数组中才能传递给这些事件处理函数。而“ mixed ”新闻的处理函数有两个参数,所以发布“ mixed ”的新闻时,参数为:

    [["Yao Ming gives Red Cliff high comments"], ["Jay and S.H.E wish Beijing Olympic success"]]

    二维数组中的第一个数组表示体育新闻,第二个数组表示娱乐新闻。

  3. 取消订阅时,必须把所有的订阅都取消。重复的订阅行为返回的句柄是不一样的,在本例中 handle1 和 handle2 是不同的,必须都注销。只有在 handle1 和 handle2 都被注销后,新闻中心发布的体育新闻才不会被这个记者接收到。

结束语

浏览器在事件处理机制上的差异使得 web 开发人员在处理事件时需异常小心,Dojo 的事件处理 API 却能在各个浏览器上工作的很好,减少了开发人员在处理跨浏览器问题上的工作量。 Dojo 参考 W3C DOM Level2 的事件模型实现的事件处理机制,即能处理 DOM 事件,也能处理用户自定义事件,而全新的“订阅 / 发布”模式也给了开发人员在处理事件时更多的选择。

 

原文:http://www.ibm.com/developerworks/cn/web/wa-lo-dojointro3/index.html

分享到:
评论

相关推荐

    dojo事件处理框架

    Dojo事件处理框架是JavaScript库Dojo Toolkit中的一个重要组成部分,它提供了一种统一的方式来管理和处理DOM事件以及JavaScript对象之间的交互。这个系统深受面向切面编程(AOP)思想的影响,尤其是其advice机制,...

    dojo的包加载机制

    其中,Dojo的包加载机制是其核心特性之一,它使得在大型应用中组织和管理JavaScript代码变得更为高效。这里我们将深入探讨Dojo的包加载机制,并结合提供的源代码和文档进行分析。 首先,Dojo的包加载机制基于AMD...

    dojo入门系列教程.rar

    dojo入门系列教程,包含入门简介,在javascript基础上介绍dojo的语法特色,ajax的dojo包装---xhr框架的编程要点, Dojo 事件机制.以及对dojo最具特色的web UI设计的全面介绍.

    Dojo基础2事件侦听器

    总结起来,Dojo的事件处理机制包括事件标准化、事件监听、事件传播控制以及发布/预定通信,这些功能为开发者提供了强大且灵活的工具,使得在Web开发中处理用户交互变得更加简单和高效。通过理解和掌握这些概念,你...

    dojo类机制实现原理分析

    ### Dojo类机制实现原理分析 #### 一、概述 Dojo框架是一个强大的JavaScript库,它不仅提供了丰富的用户界面组件,还内置了一套强大的类机制。本文旨在深入探讨Dojo类机制背后的实现原理,包括其类声明方式、继承...

    dojo中文文档-dojo手册

    Dojo还提供了强大的事件处理机制。dojo.connect允许开发者订阅和发布事件,而dojo.disconnect则可以解除事件监听。这种事件模型使得代码更具响应性和模块化。 在UI组件方面,Dojo Toolkit提供了大量预先封装好的可...

    DOJO 学习笔记 dojo

    `dojo.event` 用来绑定和解绑事件,`dojo.event.topic` 提供了消息传递机制,而 `dojo.event.browser` 是浏览器特定事件处理的接口。 `dojo.graphics.color` 模块处理颜色相关的操作,如颜色转换、解析和生成。`...

    DOJO权威指南+DOJO1.1源码

    DOJO 1.1引入了Asynchronous Module Definition (AMD)的加载机制,通过require.js实现,使得代码的组织和依赖管理更加高效。AMD允许异步加载模块,提高了页面的加载速度,并且可以更好地控制代码的执行顺序。 3. *...

    DOJO中文手册【出自dojo中国】

    3. **底层API和兼容性**:Dojo的事件系统、I/O API和通用语言增强功能构成了一个强大的编程环境,允许编写简洁且风格一致的JavaScript代码。 4. **单元测试**:Dojo提供的工具支持编写命令行式的单元测试,确保代码...

    dojo相关详细资料

    Dojo采用模块化设计,通过AMD(Asynchronous Module Definition)加载机制,可以异步地加载所需模块,提高了页面性能。此外,Dojo还支持模块的依赖管理和命名空间,使得代码组织更加清晰。 5. Dojo MHT 文件: `....

    dojo官网的源码dojo官网的源码

    `dojo/_base/kernel`是Dojo的核心模块,定义了基本的命名空间和加载机制。 2. **加载器(Loader)**:Dojo的加载器`dojo/require`和`dojo/deprecated`等,负责解析模块依赖并按需加载。在1.4.2版本中,`dojo....

    dojo练习

    同时,Dojo的事件处理机制和动画库也是其亮点,能够帮助你创建出交互性强、用户体验良好的Web应用。此外,Dojo还提供了丰富的数据存储解决方案,如dojo.store,支持与服务器的数据交换和本地数据管理。 通过上述...

    Dojo 1.10版离线参考手册

    2. **Dojo模块加载机制**: - AMD(Asynchronous Module Definition)是Dojo引入的一种模块加载方式,它允许异步加载模块,提高页面加载速度。 - `dojo/require` 和 `dojo/ready`:用于在页面加载完成后执行特定...

    dojo1.8.3官方demo

    此外,还可以探索Dojo的模块化加载机制(AMD,Asynchronous Module Definition)是如何帮助优化页面加载和提高性能的。对于想要深入Dojo开发的开发者来说,这些官方示例是宝贵的资源,能够帮助他们快速掌握Dojo的...

    dojo包和例子

    5. **dojo/data**:虽然已被`dojo/store`取代,但在一些较旧的例子中,可能还会看到`dojo/data`,它提供了一种抽象的数据访问机制,可以用于从不同数据源获取和操作数据。 6. **dijit**:Dijit是Dojo的UI组件库,...

    dojo起步学习的好例子

    3. **数据绑定 (Dojo Data)**:Dojo 提供了一种数据绑定机制,允许数据源与用户界面元素之间建立关联,实现数据的自动同步。 4. **AJAX (Asynchronous JavaScript and XML)**:Dojo 提供了简便的AJAX功能,可以轻松...

    dojo1.1 javascript框架

    4. **事件处理**:Dojo的`dojo/on`模块允许开发者监听和处理DOM事件,它支持事件委托和跨浏览器兼容性,简化了事件处理代码。 5. **Ajax通信**:Dojo的`dojo/xhr`模块提供了异步的HTTP请求功能,支持GET、POST等...

    Dojo相应的jar包

    之后,你可以利用dojo/require或AMD(Asynchronous Module Definition)机制来异步加载需要的模块。 总之,"dojo-release-1.10.0"压缩包是Dojo框架的一个完整版本,包含了开发基于Dojo的应用所需要的所有资源。无论...

    dojo-release-1.9.0-src.zip dojo javascript库源码

    Dojo 是一个强大的JavaScript工具包,它为Web开发提供了丰富的功能和组件,包括DOM操作、事件处理、Ajax交互、动画效果、模块化编程等。在"dojo-release-1.9.0-src.zip"这个压缩包中,我们获取的是Dojo 1.9.0版本的...

    Dojo1.11正式版

    1. **模块化系统**:Dojo 1.11 使用AMD(Asynchronous Module Definition)模块加载机制,允许异步加载模块,提高页面加载速度。它还支持CommonJS规范,方便开发者在不同的模块系统间切换。 2. **Dijit组件库**:...

Global site tag (gtag.js) - Google Analytics