前几章已经把最核心的实现都分解过了,这一章我们看看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. java复习集合类之List接口

    List 为有序可重复列表 实现List接口的类主要是ArrayList 下面为ArrayList的测试代码 import java.util.ArrayList; public class demo ...

  2. 有关DOM

    一般地,节点至少拥有nodeType.nodeName和nodeValue这三个基本属性. 节点类型不同,这三个属性的值也不相同 nodeType nodeType属性返回节点类型的常数值.不同的类型 ...

  3. XVII Open Cup named after E.V. Pankratiev. GP of SPb

    A. Array Factory 将下标按前缀和排序,然后双指针,维护最大的右边界即可. #include<cstdio> #include<algorithm> using ...

  4. 使EditText不要在页面打开时自动获取焦点(因为软键盘会自动弹出)

    当页面上有EditText时,第一个EditText会在页面打开时自动的获取焦点,这样带来的问题就是系统键盘会自动的弹出来. 解决方法比较简单只要为EditText的父控件设置一下就行了: andro ...

  5. bzoj3674同上(好短)

    +强在 就过了 既没有启发式又没有路径压缩,连建树都用的是代码最短的写法(什么心态,每天追求代码短) 话说回来 可持久化的数组感觉只能出类似裸题的题目,,,,藏也藏不住啊 #include <c ...

  6. Cloud Engine:大杀器如何炼成

    郑昀(微博:http://weibo.com/yunzheng) 创建于2016/6/18 最后更新于2016/6/19 点击查看我的<如何从零搭建一个技术平台>,这是一个系列.转载时请注 ...

  7. WCF自动添加消息头

    客户端自定义消息查看器实现IClientMessageInspector接口在消息发送之前添加消息头 class ClientMessageInspector : System.ServiceMode ...

  8. Node.js抓取网页

    前几天四六级成绩出来(然而我没考),用Node.js做了一个模拟表单提交并抓取数据的Web 总结一下用到的知识,简单的网页抓取大概就是这个流程了 发送Get或Post请求 表单提交,首先弄到原网页提交 ...

  9. 关于DOM的一些笔记(一)

    这篇文章整理的是关于DOM的一些学习笔记,这样以后查找起来也方便许多.(以前js看的是入门经典和DOM编程艺术,现在在看高级程序设计,本文就以高级程序为主整理) 1.Node (1):类型 node. ...

  10. Struts 2的OGNL的根对象

    Struts2中的OGNL表达式语言是对Xwork的OGNL的封装.我们要理解一下几点: 1. Struts2中将ActionContext作为OGNL的上下文环境(ActionContext内部含有 ...