require(["dojo/on","dojo/_base/window"],function(on,win){ var signal = on(win.doc,"click",function(){ // remove listener after first event signal.remove(); // do something else... }); });
require("dojo/on",function(on){ on(element,"dblclick,touchend",function(e){ // handle either event }); });
require(["dojo/on","dojo/_base/window","dojo/query"],win){
on(win.doc,".myClass:click",clickHandler);
});
require(["dojo/on","dojo/mouse","dojo/query!css2"],mouse){
on(node,on.selector(".myClass",mouse.enter),myClassHoverHandler);
});
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,this); };
下面来看一下事件解析的过程:
- 如果type是方法,则交给type自身去处理;比如touch.press 、on.selector
- 多事件的处理;事件可能是通过逗号键分隔的字符串,所以将其变成字符串数组
- 对于事件数组依次调用on.parse
- 添加事件监听器
on.parse = function(target,matchesTarget){ 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); };
接着看一下事件监听器的处理过程:
- 处理事件委托,dojo中事件委托的书写格式为:“selector:eventType”,直接交给on.selector处理
- 对与touchevent事件的处理,具体分析以后再说
- 对于stopImmediatePropagation的修正
- 支持addEventListener的浏览器,使用浏览器自带的接口进行处理
- 对于不支持addEventListener的浏览器进行进入fixAttach函数
View Code
@H_403_6@ 对于上面的分析我们可以得出几个结论:
- 对于没有特殊EventType和普通事件都用addEventListener来添加事件了。
- 而特殊EventType,则用了另一种方式来添加事件(fixAttach)。
- 对于事件委托交给了on.selector处理
来详细的看一下fixAttach:
1、修正事件监听器,该过程返回一个闭包,闭包中对event对象进行修正,主要有一下几方面:
- target
- currentTarget
- relatedTarget
- stopPropagation
- preventDefault
- event的坐标位置兼容放到了dom-geometry的normalizeEvent中处理
- keycode与charcode的处理
View Code
@H_403_6@ 关于aspect.after的具体工作原理,请看我的这篇文章:Javascript事件机制兼容性解决方案
@H_403_6@
@H_403_6@ 接下来我们看一下委托的处理:
@H_403_6@
@H_403_6@ 为document绑定click事件,click事件出发后,判断event.target是否满足选择符“button.myclass”,若满足则执行clickHandler。为什么要判断event.target是否满足选择条件,document下可能有a、也可能有span,我们只需要将a的click委托给document,所以要判断是否满足选择条件。委托过程的处理主要有两个函数来解决:on.selector、on.matches.
@H_403_6@
@H_403_6@
@H_403_6@ 红框部分就是判断event.target是否匹配选择符,如果匹配则触发事件回调clickHandler.
@H_403_6@
on.matches中做了以下几件事:
- 获取有效的matchesTarget,matchesTarget是一个拥有matches方法的对象,默认取dojo.query
- 对textNode做处理
- 检查event.target的祖先元素是否满足匹配条件
View Code
@H_403_6@ 对比dojo与jquery的事件处理过程,可以发现jQuery在事件存储上更上一筹:
@H_403_6@ dojo直接绑定到dom元素上,jQuery并没有将事件处理函数直接绑定到DOM元素上,而是通过.data存储在缓存.cahce上。
@H_403_6@ 声明绑定的时候:
- 首先为DOM元素分配一个唯一ID,绑定的事件存储在
- 当事件触发时eventHandle被执行,eventHandle再去$.cache中寻找曾经绑定的事件处理函数并执行,这个过程由 jQuery.event. trigger 和 jQuery.event.handle实现。
- 事件的销毁则由jQuery.event.remove 实现,remove对缓存$.cahce中存储的事件数组进行销毁,当缓存中的事件全部销毁时,调用removeEventListener/ detachEvent销毁绑定在DOM元素上的事件处理函数eventHandle。