解密jQuery事件核心 - 模拟事件(四)
前几章已经把最核心的实现都分解过了,这一章我们看看jQuery是如何实现事件模拟的
在Internet Explorer 8和更低,一些事件change 和 submit本身不冒泡,但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为了实现兼容统一,可谓煞费苦心了,把事件冒泡与捕获都统一模拟了一遍
- jQuery为统一原生Event对象而封装的jQuery.Event类,封装了preventDefault,stopPropagation,stopImmediatePropagation原生接口,可以直接捕获到用户的行为
- 由核心组件 jQuery.cache 实现注册事件处理程序的存储,实际上绑定在 DOM元素上的事件处理程序只有一个,即 jQuery.cache[elem[expando]].handle 中存储的函数,该函数在内部调用 jQuery.event.dispatch(event) 实现对该DOM元素特定事件的缓存的访问,并依次执行这些事件处理程序。
- jQuery.event.add(elem, types, handler, data, selector) 方法用于给特定elem元素添加特定的事件 types([type.namespace, type.namespace, ...])的事件处理程序 handler, 通过第四个参数 data 增强执行当前 handler 事件处理程序时的 $event.data 属性,以提供更灵活的数据通讯,而第五个元素用于指定基于选择器的委托事件
- namespace 命名空间机制,namespace 机制可以对事件进行更为精细的控制,开发人员可以指定特定空间的事件,删除特定命名空间的事件,以及触发特定命名空间的事件。这使得对事件处理机制的功能更加健
- jQuert.event.special 对象用于某些事件类型的特殊行为和属性。比如 load 事件拥有特殊的 noBubble 属性,可以防止该事件的冒泡而引发一些错误。总的来说,有这样一些方法和属性:
- jQuery.event.simulate(type, elem, event, bubble)模拟事件并立刻触发方法,可用于在DOM元素 elem 上模拟自定义事件类型 type,参数 bubble用于指定该事件是否可冒泡,event 参数表示 jQuery 事件对象 $event。 模拟事件通过事件对象的isSimulated属性为 true 表示这是模拟事件。该方法内部调用 trigger() 逻辑 或 dispatch() 逻辑立刻触发该模拟事件。该方法主要用于修正浏览器事件的兼容性问题,比如模拟出可冒泡的 focusin/ focusout 事件,修正IE中 change 事件的不可冒泡问题,修正IE中 submit事件不可冒泡问题
- jQuery.event.dispatch(event) 方法在处理事件委托机制时,依赖委托节点在DOM树的深度安排优先级,委托的DOM节点层次越深,其执行优先级越高。而其对于stopPropagation的处理有些特殊,在事件委托情况下并不一定会调用绑定在该DOM元素上的该类型的所有事件处理程序,而依赖于委托的事件处理程序的执行结果,如果低层委托的事件处理程序声明了停止冒泡,那么高层委托的事件以及自身绑定事件就不会被执行,这拓展了 DOM 委托机制的功能。
- jQuery.event.trigger(event | type, data, elem, onlyHandlers) 方法提供开发人员以程序方式触发特定事件的接口,该方法的第一个参数可以是 $event/ event 对象 ,也可以是某个事件类型的字符串 type; 第二个参数 data 用于扩展该事件触发时事件处理程序的参数规模,用于传递一些必要的信息。 elem参数表示触发该事件的DOM元素;最后该方法在默认情况下,其事件会冒泡,并且在有默认动作的情况下执行默认行为,但是如果指定了 onlyHandlers 参数,该方法只会触发绑定在该DOM元素上的事件处理程序,而不会引发冒泡和默认动作,也不会触发特殊的 trigger 行为。
- …………………
解密jQuery事件核心 - 模拟事件(四)的更多相关文章
- JS 中的自定义事件和模拟事件
在 JS 中模拟事件指的是模拟 JS 中定义的一些事件,例如点击事件,键盘事件等. 自定义事件指的是创建一个自定义的,JS 中之前没有的事件. 接下来分别说一下创建这两种事件的方法. 创建自定义事件 ...
- jQuery 移除事件与模拟事件
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <meta http ...
- HTML 事件(四) 模拟事件操作
本篇主要介绍HTML DOM中事件的模拟操作. 其他事件文章 1. HTML 事件(一) 事件的介绍 2. HTML 事件(二) 事件的注册与注销 3. HTML 事件(三) 事件流与事件委托 4. ...
- Javascript高级编程学习笔记(71)—— 模拟事件(1)DOM事件模拟
事件,指的是网页中某个特定的交互时刻 一般来说事件由浏览器厂商负责提供,一般由用户操作或者其它浏览器功能来触发 但是有一类特殊的事件,那就是由我们开发人员通过JS触发的事件 这些事件和浏览器创建的事件 ...
- 解密jQuery事件核心 - 绑定设计(一)
说起jQuery的事件,不得不提一下Dean Edwards大神 addEvent库,很多流行的类库的基本思想从他那儿借来的 jQuery的事件处理机制吸取了JavaScript专家Dean Edwa ...
- 解密jQuery事件核心 - 委托设计(二)
第一篇 http://www.cnblogs.com/aaronjs/p/3444874.html 从上章就能得出几个信息: 事件信息都存储在数据缓存中 对于没有特殊事件特有监听方法和普通事件都用ad ...
- 解密jQuery事件核心 - 自定义设计(三)
接上文http://www.cnblogs.com/aaronjs/p/3447483.html 本文重点:自定义事件 “通过事件机制,可以将类设计为独立的模块,通过事件对外通信,提高了程序的开发效率 ...
- 第一百七十一节,jQuery,高级事件,模拟操作,命名空间,事件委托,on、off 和 one
jQuery,高级事件,模拟操作,命名空间,事件委托,on.off 和 one 学习要点: 1.模拟操作 2.命名空间 3.事件委托 4.on.off 和 one jQuery 不但封装了大量常用的事 ...
- 锋利的jQuery ——jQuery中的事件和动画(四)
一.jQuery中的事件 1)加载DOM $(document).ready()和window.onload的区别 1>执行时机 $(document).ready(){} 方法内注册的事件, ...
随机推荐
- windows系统时间(SYSTEMTIME)
GetSystemTime函数获得当前的UTC时间,GetLocalTime获得当前的本地时间 UTC是协调世界时(Universal Time Coordinated)英文缩写,是由国际无线电咨询委 ...
- ssh自动输入密码脚本 切换目录脚本
利用expect的,首先查看expect,命令:which expect #!/usr/bin/expect -f spawn ssh 用户名@ip地址 expect "assword:&q ...
- mysql中生产表格多列统计问题
for Example: select date_format(date,'%Y-%m-%d') as day, count(case when xinghao='a' then 1 end) as ...
- js兼容总结之获取非行间样式
非行间样式案例 #div1 { width: 200px; height: 200px; background: red; } IE获取非行间样式 var oDiv = document.getEle ...
- 区间DP LightOJ 1422 Halloween Costumes
http://lightoj.com/volume_showproblem.php?problem=1422 做的第一道区间DP的题目,试水. 参考解题报告: http://www.cnblogs.c ...
- Androidannotations框架
Java注解: 注解(Annotation),也叫元数据.一种代码级别的说明.它是JDK1.5及以后版本引入的一个特性,与类.接口.枚举是在同一个层次.它可以声明在包.类.字段.方法.局部变量. ...
- 2016huasacm暑假集训训练五 F - Monkey Banana Problem
题目链接:http://acm.hust.edu.cn/vjudge/contest/126708#problem/F 题意:求至上而下一条路径的所经过的值得和最大值,这题比赛时就出了 但当时看不懂题 ...
- WCF 程序入门
WCF是微软公司推出的符合SOA思想的分布式应用程序技术框架和编程模型,是建立在消息通信这一概念基础上运行的一个运行时服务系统. WCF编程模型的目标是实现以下两个实体之间的通信:WCF服务端和WCF ...
- 工作总结_sql
今天客户叫导入数据,因为存在特殊字符,快把我给玩死了,,所以请教...总结 sql 数据导入excel 存在特殊字符引起的数据缺失 利用字符方式 : select a.OpenID+', ...
- 利用GeoIP数据库及API进行地理定位查询
GeoIP数据库下载地址:http://geolite.maxmind.com/download/geoip/database/GeoLiteCountry/GeoIP.dat.gz. 首先,在Max ...