前几章已经把最核心的实现都分解过了,这一章我们看看jQuery是如何实现事件模拟的

在Internet Explorer 8和更低,一些事件changesubmit本身不冒泡,但jQuery修改这些冒泡,创建一致的跨浏览器的行为。

焦点事件

blur :

在这个事件触发前,元素已经失去焦点,不冒泡,同步触发。target 指向当前失去焦点的元素。

focus:

在这个事件触发前,元素已经得到焦点,不冒泡,同步触发。target 指向当前得到焦点的元素。


与此同时DOM Level 3 事件模块 还定义了 focusin ,focusout 以及 DOMFocusIn ,DOMFocusOut 四个事件。

focusin :

在当前元素获得焦点前以及相关元素失去焦点前触发,可冒泡,同步触发。target 指向当前将要获得焦点的元素,relatedTarget 指向失去焦点的元素

focusout :

在当前失去焦点前触发,可冒泡,同步触发。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?


jQuery.event.special方法

这个方法在event.add,event.dispatch等几个事件的处理地方都会被调用到,jQuert.event.special 对象用于某些事件类型的特殊行为和属性

换句话说就是某些事件不是大众化的的事件,不能一概处理,比如 load 事件拥有特殊的 noBubble 属性,可以防止该事件的冒泡而引发一些错误

所以需要单独针对处理,但是如果都写成判断的形式,显然代码结构就不合理了,而且不方便提供给用户自定义扩展

在webkit下的截图,特殊事件类型

大体上针对9种事件,不同情况下处理hack,我们具体分析下焦点事件兼容冒泡处理,处理大同小异


jQuery.event 事件机制 focusin/ focusout 事件

针对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方法

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为了实现兼容统一,可谓煞费苦心了,把事件冒泡与捕获都统一模拟了一遍

  1. jQuery为统一原生Event对象而封装的jQuery.Event类,封装了preventDefault,stopPropagation,stopImmediatePropagation原生接口,可以直接捕获到用户的行为
  2. 由核心组件 jQuery.cache 实现注册事件处理程序的存储,实际上绑定在 DOM元素上的事件处理程序只有一个,即 jQuery.cache[elem[expando]].handle 中存储的函数,该函数在内部调用 jQuery.event.dispatch(event) 实现对该DOM元素特定事件的缓存的访问,并依次执行这些事件处理程序。
  3. jQuery.event.add(elem, types, handler, data, selector) 方法用于给特定elem元素添加特定的事件 types([type.namespace, type.namespace, ...])的事件处理程序 handler, 通过第四个参数 data 增强执行当前 handler 事件处理程序时的 $event.data 属性,以提供更灵活的数据通讯,而第五个元素用于指定基于选择器的委托事件
  4. namespace 命名空间机制,namespace 机制可以对事件进行更为精细的控制,开发人员可以指定特定空间的事件,删除特定命名空间的事件,以及触发特定命名空间的事件。这使得对事件处理机制的功能更加健
  5. jQuert.event.special 对象用于某些事件类型的特殊行为和属性。比如 load 事件拥有特殊的 noBubble 属性,可以防止该事件的冒泡而引发一些错误。总的来说,有这样一些方法和属性:
  6. jQuery.event.simulate(type, elem, event, bubble)模拟事件并立刻触发方法,可用于在DOM元素 elem 上模拟自定义事件类型 type,参数 bubble用于指定该事件是否可冒泡,event 参数表示 jQuery 事件对象 $event。 模拟事件通过事件对象的isSimulated属性为 true 表示这是模拟事件。该方法内部调用 trigger() 逻辑 或 dispatch() 逻辑立刻触发该模拟事件。该方法主要用于修正浏览器事件的兼容性问题,比如模拟出可冒泡的 focusin/ focusout 事件,修正IE中 change 事件的不可冒泡问题,修正IE中 submit事件不可冒泡问题
  7. jQuery.event.dispatch(event) 方法在处理事件委托机制时,依赖委托节点在DOM树的深度安排优先级,委托的DOM节点层次越深,其执行优先级越高。而其对于stopPropagation的处理有些特殊,在事件委托情况下并不一定会调用绑定在该DOM元素上的该类型的所有事件处理程序,而依赖于委托的事件处理程序的执行结果,如果低层委托的事件处理程序声明了停止冒泡,那么高层委托的事件以及自身绑定事件就不会被执行,这拓展了 DOM 委托机制的功能。
  8. jQuery.event.trigger(event | type, data, elem, onlyHandlers) 方法提供开发人员以程序方式触发特定事件的接口,该方法的第一个参数可以是 $event/ event 对象 ,也可以是某个事件类型的字符串 type; 第二个参数 data 用于扩展该事件触发时事件处理程序的参数规模,用于传递一些必要的信息。 elem参数表示触发该事件的DOM元素;最后该方法在默认情况下,其事件会冒泡,并且在有默认动作的情况下执行默认行为,但是如果指定了 onlyHandlers 参数,该方法只会触发绑定在该DOM元素上的事件处理程序,而不会引发冒泡和默认动作,也不会触发特殊的 trigger 行为。
  9. …………………

解密jQuery事件核心 - 模拟事件(四)的更多相关文章

  1. JS 中的自定义事件和模拟事件

    在 JS 中模拟事件指的是模拟 JS 中定义的一些事件,例如点击事件,键盘事件等. 自定义事件指的是创建一个自定义的,JS 中之前没有的事件. 接下来分别说一下创建这两种事件的方法. 创建自定义事件 ...

  2. jQuery 移除事件与模拟事件

    <!DOCTYPE html> <html> <head> <meta charset="utf-8"> <meta http ...

  3. HTML 事件(四) 模拟事件操作

    本篇主要介绍HTML DOM中事件的模拟操作. 其他事件文章 1. HTML 事件(一) 事件的介绍 2. HTML 事件(二) 事件的注册与注销 3. HTML 事件(三) 事件流与事件委托 4.  ...

  4. Javascript高级编程学习笔记(71)—— 模拟事件(1)DOM事件模拟

    事件,指的是网页中某个特定的交互时刻 一般来说事件由浏览器厂商负责提供,一般由用户操作或者其它浏览器功能来触发 但是有一类特殊的事件,那就是由我们开发人员通过JS触发的事件 这些事件和浏览器创建的事件 ...

  5. 解密jQuery事件核心 - 绑定设计(一)

    说起jQuery的事件,不得不提一下Dean Edwards大神 addEvent库,很多流行的类库的基本思想从他那儿借来的 jQuery的事件处理机制吸取了JavaScript专家Dean Edwa ...

  6. 解密jQuery事件核心 - 委托设计(二)

    第一篇 http://www.cnblogs.com/aaronjs/p/3444874.html 从上章就能得出几个信息: 事件信息都存储在数据缓存中 对于没有特殊事件特有监听方法和普通事件都用ad ...

  7. 解密jQuery事件核心 - 自定义设计(三)

    接上文http://www.cnblogs.com/aaronjs/p/3447483.html 本文重点:自定义事件 “通过事件机制,可以将类设计为独立的模块,通过事件对外通信,提高了程序的开发效率 ...

  8. 第一百七十一节,jQuery,高级事件,模拟操作,命名空间,事件委托,on、off 和 one

    jQuery,高级事件,模拟操作,命名空间,事件委托,on.off 和 one 学习要点: 1.模拟操作 2.命名空间 3.事件委托 4.on.off 和 one jQuery 不但封装了大量常用的事 ...

  9. 锋利的jQuery ——jQuery中的事件和动画(四)

    一.jQuery中的事件 1)加载DOM $(document).ready()和window.onload的区别 1>执行时机 $(document).ready(){}  方法内注册的事件, ...

随机推荐

  1. Unity3D 脚本编译器无法关联VisualStudio2012解决办法

    开发环境:Win8 + Unity 4.34f1 +Visual Studio2012 旗舰版 解决办法:   1.创建一个start.bat文件,内容为:[start "" %* ...

  2. 软件工程:Wordcount程序作业

    由于时间的关系,急着交作业,加上这一次也不是那么很认真的去做,草草写了“Wordcount程序”几个功能,即是 .txt文件的读取,能计算出文件内容的单词数,文件内容的字符数,及行数. 这次选用C来做 ...

  3. UML类图关系--继承(泛化)、实现、关联、聚合、组合、依赖

    在UML类图中,常见的有以下几种关系:  泛化(Generalization),  实现(Realization),关联(Association),聚合(Aggregation),组合(Composi ...

  4. Mybatis添加到Spring

    一.准备工作: 1.1 添加相应的jar包依赖: 这里用到了两个jar包,一个是mybatis的,另一个是mybatis-spring的,代码如下: 1 2 3 4 5 6 7 8 9 10 < ...

  5. java web(七)Cookie的简单使用

    一.概述 测试 //1.创建一个Cookie对象    //Cookie cookie1=new Cookie("name","xrk");    //2.调用 ...

  6. 【hihoCoder】1288 : Font Size

    题目:http://hihocoder.com/problemset/problem/1288 手机屏幕大小为 W(宽) * H(长),一篇文章有N段,每段有ai个字,要求使得该文章占用的页数不超过P ...

  7. 谷歌浏览器允许ajax跨域以非安全模式打开

    最近使用ajax的时候,因为是在本地测试调用 后台时一直会报错. 解决方案:用谷歌浏览器 以非安全的模式打开 在cmd命令行中 cd 到谷歌的安装目录下 (右键 属性 复制路径) 然后在 运行如下命令 ...

  8. python将图片转换为Framebuffer裸数据格式(终端显示图片)

    要在ubuntu终端显示图片或者在板子的LCD显示图片,Framebuffer是一个简单易用的接口,直接写入像素信息即可. 但普通的图片带有头部信息或者编码格式不同,直接送入Framebuffer是显 ...

  9. OUTLOOK 发生错误0x8004010D

    问题:    outlook 2003 在接收邮件时报错: “正在接收”报告了错误(0x8004010D):“在包含您的数据文件的驱动器上,磁盘空间不足.请清空“已删除邮件”文件夹或删除某些文件以释放 ...

  10. IDT HOOK思路整理

    IDT(中断描述符表)分为IRQ(真正的硬件中断)和软件中断(又叫异常). HOOK的思路为,替换键盘中断处理的函数地址为自己的函数地址.这样在键盘驱动和过滤驱动之前就可以截获键盘输入. 思路确定之后 ...