前几章已经把最核心的实现都分解过了,这一章咱们看看jQuery是如何实现事件模拟的html
在Internet Explorer 8和更低,一些事件change
和 submit
自己不冒泡,但jQuery修改这些冒泡,建立一致的跨浏览器的行为。web
blur :浏览器
在这个事件触发前,元素已经失去焦点,不冒泡,同步触发。target 指向当前失去焦点的元素。缓存
focus:函数
在这个事件触发前,元素已经获得焦点,不冒泡,同步触发。target 指向当前获得焦点的元素。spa
与此同时DOM Level 3 事件模块 还定义了 focusin ,focusout 以及 DOMFocusIn ,DOMFocusOut 四个事件。3d
focusin :代理
在当前元素得到焦点前以及相关元素失去焦点前触发,可冒泡,同步触发。target 指向当前将要得到焦点的元素,relatedTarget 指向失去焦点的元素code
focusout :htm
在当前失去焦点前触发,可冒泡,同步触发。target 指向当前将要失去焦点的元素,relatedTarget 指向将要失去焦点的元素。
DOMFocusIn :
在这个事件触发前,元素已经获得焦点,可冒泡,同步触发。target 指向当前获得焦点的元素。
DOMFocusOut :
在这个事件触发前,元素已经没有焦点,可冒泡,同步触发。target 指向当前失去焦点的元素
1, 全部 IE 版本均支持focusin/focusout事件(注意:IE6/7/8中不支持el.addEventListener方法)。
2, Opera 最强悍即支持attachEvent,又支持addEventListener。且这两种方式添加事件均支持focusin/focusout事件。
3, Safari/Chrome 给人一个惊喜,虽然el.onfocusin方式不支持,但 addEventListener方式却支持。所以想让Safari/Chrome中支持focusin事件,只能使用addEventListener方式添加事件。
4, Firefox 任何一种添加事件方式都不支持 focusout/focuso
那么如何在全部的平台上都兼容focusin/focusout?
这个方法在event.add,event.dispatch等几个事件的处理地方都会被调用到,jQuert.event.special 对象用于某些事件类型的特殊行为和属性
换句话说就是某些事件不是大众化的的事件,不能一律处理,好比 load 事件拥有特殊的 noBubble 属性,能够防止该事件的冒泡而引起一些错误
因此须要单独针对处理,可是若是都写成判断的形式,显然代码结构就不合理了,并且不方便提供给用户自定义扩展
在webkit下的截图,特殊事件类型
大致上针对9种事件,不一样状况下处理hack,咱们具体分析下焦点事件兼容冒泡处理,处理大同小异
针对focusin/ focusout 事件jQuery.event.special扩充2组处理机制,
special.setup方法主要是来在Firefox中模拟focusin和focusout事件的,由于各大主流浏览器只有他不支持这两个事件。
因为这两个方法支持事件冒泡,因此能够用来进行事件代理
var attaches = 0, handler = function( event ) { jQuery.event.simulate( fix, event.target, jQuery.event.fix( event ), true ); }; jQuery.event.special[ fix ] = { setup: function() { if ( attaches++ === 0 ) { document.addEventListener( orig, handler, true ); } }, teardown: function() { if ( --attaches === 0 ) { document.removeEventListener( orig, handler, true ); } } };
前面的分析咱们就知道经过事件最终都是经过add方法绑定的,也就是addEventListener方法绑定的,可是在add方法以前会有一个过滤分支
之前看不懂代码,如今回过来恍然大悟了,原来这个方法是这样用的
因此最终代码会跑到各类的Hack中了,
可见对focusin/ focusout 的处理,没有用通用的方法,并且是直接用的special.setup中的绑定
几个重点
1 绑定的是focusin/ focusout 事件,内部确换成了focus/blur事件
2 document.addEventListener( orig, handler, true );事件绑在document上,最后是true,用的捕获绑定
3 jQuery.event.simulate( fix, event.target, jQuery.event.fix( event ), true );方法
由于火狐不支持focusin/ focusout事件,因此要找个全部浏览器都兼容相似事件,对了那就是focus/blur,
可是focus/blur不能冒泡丫,怎么办?
咱不是还有捕获吗?
那么利用捕获怎么模拟出冒泡呢?
jQuery.event.simulate = function( type, elem, event, bubble ) { // 重写事件 var e = jQuery.extend( new jQuery.Event(), event, { type: type, isSimulated: true, originalEvent: {} } ); // 若是要冒泡 if ( bubble ) { // 利用jQuery.event.trigger模拟触发事件 jQuery.event.trigger( e, null, elem ); } else { // 不然利用jQuery.event.dispatch来执行处理 jQuery.event.dispatch.call( elem, e ); } // 若是须要阻止默认操做,则阻止 if ( e.isDefaultPrevented() ) { event.preventDefault(); } }
能够看到focusin/ focusout 可冒泡事件实现原理是
1 focusin 事件添加事件处理程序时,jQuery 会在 document 上会添加 handler 函数
2 在事件捕获阶段监视特定元素的 focus/ blur 动做,捕获行为发生在 document 对象上,这样才能有效地实现全部元素都能能够冒泡的事件。
3 程序监视到存在 focus/ blur 行为,就会触发绑定在 document 元素上的事件处理程序,该事件处理程序在内部调用 simulate 逻辑触发事件冒泡,以实现咱们但愿的能够冒泡事件。
4 以后利用jQuery.event.trigger模拟触发事件,把从target-document的元素都过滤出来,分析每一个节点上是否绑定了事件句柄,依次处理,按照必定的规范,好比是否有事件阻止之类的,这里就再也不重复分析了jQuery.event.trigger http://www.cnblogs.com/aaronjs/p/3452279.html
咋一看其实原理都挺简单的, 可是jQuery为了实现兼容统一,可谓煞费苦心了,把事件冒泡与捕获都统一模拟了一遍