dojo事件驱动编程之事件绑定
转载博客:http://www.cnblogs.com/dojo-lzz/p/4687961.html dojo事件驱动编程之事件绑定什么是事件驱动? 事件驱动编程是以事件为第一驱动的编程模型,模块被动等待通知(notification),行为取决于外来的突发事件,是事件驱动的,符合事件驱动式编程(Event-Driven Programming,简称EDP)的模式。 何谓事件?通俗地说,它是已经发生的某种令人关注的事情。在软件中,它一般表现为一个程序的某些信息状态上的变化。基于事件驱动的系统一般提供两类的内建事件(built-in event):一类是底层事件(low-level event)或称原生事件(native event),在用户图形界面(GUI)系统中这类事件直接由鼠标、键盘等硬件设备触发;一类是语义事件(semantic event),一般代表用户的行为逻辑,是若干底层事件的组合。比如鼠标拖放(drag-and-drop)多表示移动被拖放的对象,由鼠标按下、鼠标移动和鼠标释放三个底层事件组成。 还有一类用户自定义事件(user-defined event)。它们可以是在原有的内建事件的基础上进行的包装,也可以是纯粹的虚拟事件(virtual event)。除此之外,编程者不但能定义事件,还能产生事件。虽然大部分事件是由外界激发的自然事件(natural event),但有时程序员需要主动激发一些事件,比如模拟用户鼠标点击或键盘输入等,这类事件被称为合成事件(synthetic event)。这些都进一步丰富完善了事件体系和事件机制,使得事件驱动式编程更具渗透性。
上图为一个典型的事件驱动式模型。事件处理器事先在关注的事件源上注册,后者不定期地发表事件对象,经过事件管理器的转化(translate)、合并(coalesce)、排队(enqueue)、分派(dispatch)等集中处理后,事件处理器接收到事件并对其进行相应处理。通过事件机制,事件源与事件处理器之间建立了松耦合的多对多关系:一个事件源可以有多个处理器,一个处理器可以监听多个事件源。再换个角度,把事件处理器视为服务方,事件源视为客户方,便是一个client-server模式。每个服务方与其客户方之间的会话(session)是异步的,即在处理完一个客户的请求后不必等待下一请求,随时可切换(switch)到对其他客户的服务。 在web环境中事件源由DOM充当,事件管理器对于web开发者来说是透明的,由浏览器内部管理,事件处理器便是我们绑定在dom事件中的回调函数。 Web事件处理流程 DOM2.0模型将事件处理流程分为三个阶段:一、事件捕获阶段,二、事件目标阶段,三、事件起泡阶段。如图:
事件捕获:当某个元素触发某个事件(如onclick),顶层对象document就会发出一个事件流,随着DOM树的节点向目标元素节点流去,直到到达事件真正发生的目标元素。在这个过程中,事件相应的监听函数是不会被触发的。 事件目标:当到达目标元素之后,执行目标元素该事件相应的处理函数。如果没有绑定监听函数,那就不执行。 事件起泡:从目标元素开始,往顶层元素传播。途中如果有节点绑定了相应的事件处理函数,这些函数都会被一次触发。如果想阻止事件起泡,可以使用e.stopPropagation()(Firefox)或者e.cancelBubble=true(IE)来组织事件的冒泡传播。 然而在此末法时代,浏览器两大派别对于事件方面的处理,常常让前端程序员大伤脑筋,所以任何前端库首先要对事件机制进行统一。 dojo中的事件绑定 dojo事件体系能够帮我们解决哪些问题?
dojo中处理浏览器事件的代码位于dojo/on模块中,在官网中可以查看该函数的签名:
其中type可以是一个事件名称如:“click” require(["dojo/on","dojo/_base/window"],function(on,win){ var signal = on(win.doc,"click",255); line-height:1.5!important">function(){ // remove listener after first event signal.remove(); do something else... }); }); 亦可以是由逗号分隔的多个事件名组成的字符串,如:"dblclick,click" require("dojo/on",255); line-height:1.5!important">function(on){ on(element,"dblclick,touchend",255); line-height:1.5!important">function(e){ handle either event }); }); 亦可以是由冒号分隔"selector:eventType"格式进行事件委托使用的字符串,如:".myClass:click" ".myClass:click",clickHandler);
});
亦可以是一个函数,如:touch.press、on.selector() ".myClass",mouse.enter),myClassHoverHandler);
});
查看一下on函数的源码 var on = function(target,type,listener,dontFix){ if(typeof target.on == "function" && typeof type != "function" && !target.nodeType){ delegate to the target's on() method,so it can handle it's own listening if it wants (unless it is DOM node and we may be dealing with jQuery or Prototype's incompatible addition to the Element prototype return target.on(type,listener); } delegate to main listener code return on.parse(target,addListener,dontFix,255); line-height:1.5!important">this); };
如果target自己拥有on方法则调用target自己的on方法,如_WidgetBase类有自己的on方法,再比如jquery对象也会有自己的on方法,此处this关键字指向window。
下面来看一下事件解析的过程:
on.parse = if(type.call){ event handler function on(node,touch.press,touchListener); return type.call(matchesTarget,target,listener); } if(type instanceof Array){ allow an array of event names (or event handler functions) events = type; }else if(type.indexOf(",") > -1){ we allow comma delimited event names,so you can register for multiple events at once var events = type.split(/s*,s*/); } if(events){ var handles = []; var i = 0; var eventName; while(eventName = events[i++]){ handles.push(on.parse(target,eventName,matchesTarget)); } handles.remove = function(){ for(var i = 0; i < handles.length; i++){ handles[i].remove(); } }; return handles; } return addListener(target,matchesTarget); };
接着看一下事件监听器的处理过程:
View Code
对于上面的分析我们可以得出几个结论:
来详细的看一下fixAttach:
1、修正事件监听器,该过程返回一个闭包,闭包中对event对象进行修正,主要有一下几方面:
2、对于低版本浏览器防止在frames和为链接到DOM树中元素添加事件时引起的内存泄露,这里自定义一个Event对象,将所有的事件监听器作为属性添加到这个Event对象上。
3、不在2条件中的情况使用aspect.after构造一个函数链来存放事件监听器,这就保证了监听器的调用顺序与添加顺序一致。
View Code
关于aspect.after的具体工作原理,请看我的这篇文章:Javascript事件机制兼容性解决方案
接下来我们看一下委托的处理:
为document绑定click事件,click事件出发后,判断event.target是否满足选择符“button.myclass”,若满足则执行clickHandler。为什么要判断event.target是否满足选择条件,document下可能有a、也可能有span,我们只需要将a的click委托给document,所以要判断是否满足选择条件。委托过程的处理主要有两个函数来解决:on.selector、on.matches.
on.selector中返回一个匿名函数,匿名函数中做了几件事:
红框部分就是判断event.target是否匹配选择符,如果匹配则触发事件回调clickHandler.
on.matches中做了以下几件事:
View Code
对比dojo与jquery的事件处理过程,可以发现jQuery在事件存储上更上一筹: dojo直接绑定到dom元素上,jQuery并没有将事件处理函数直接绑定到DOM元素上,而是通过.data存储在缓存.cahce上。 声明绑定的时候:
执行绑定的时候:
以上就是dojo事件模块的主要内容,如果结合Javascript事件机制兼容性解决方案来看的话,更有助于理解dojo/on模块。 (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |