那么jQuery事件处理机制能帮我们处理那些问题?

  1. 毋容置疑首先要解决浏览器事件兼容问题
  2. 可以在一个事件类型上添加多个事件处理函数,可以一次添加多个事件类型的事件处理函数
  3. 提供了常用事件的便捷方法
  4. 支持自定义事件
  5. 扩展了组合事件
  6. 提供了统一的事件封装、绑定、执行、销毁机制
  7. ……

为了更深入的理解幕后的实现,所以先整理整体的结构思路,从1.7后就去除了live绑定,所以现在的整个事件的API

如图:


jQuery的事件绑定有多个方法可以调用,以click事件来举例:

  • click方法
  • bind方法
  • delegate方法
  • on方法
$('#foo').click(function(){ })

$('#foo').bind('click',function(){ })

$("foo").delegate("td", "click", function() { });

$("foo").on("click", "td", function() { });

以上四种绑定都能达到同一样的效果,但是各自又有什么区别,内部又是如何实现?


源码分析

click方式

jQuery.each( ("blur focus focusin focusout load resize scroll unload 

click

 dblclick " +
"mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave " +
"change select submit keydown keypress keyup error contextmenu").split(" "), function( i, name ) { // Handle event binding
jQuery.fn[ name ] = function( data, fn ) {
return arguments.length > 0 ?
this.on( name, null, data, fn ) :
this.trigger( name );
};
});

源码很简单,合并15种事件统一增加到jQuery.fn上

内部调用this.on / this.trigger

bind方式

bind: function( types, data, fn ) {
return this.on( types, null, data, fn );
},
unbind: function( types, fn ) {
return this.off( types, null, fn );
},

同样调用的this.on/this.off

delegate方式

delegate: function( selector, types, data, fn ) {
return this.on( types, selector, data, fn );
},
undelegate: function( selector, types, fn ) {
// ( namespace ) or ( selector, types [, fn] )
return arguments.length === 1 ? this.off( selector, "**" ) : this.off( types, selector || "**", fn );
}

同样调用的this.on/this.off

one方式

one: function( types, selector, data, fn ) {
return this.on( types, selector, data, fn, 1 );
},

还是this.on

可见以上的接口只是修改了不同的传递参数,最后都交给on实现的


实现最简单的事件委托

给父元素绑定事件,子元素也能响应

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=gb2312" />
<!-----------------------------测试代码开始-------------------------------->
<div id='p' style="width:500px;height: 500px;background:red">

<div id="test" style="width:50px;height: 50px;background:chartreuse">点击</div>

</div>

<span id="preserve2b9f1efd3c03447e90ebbff63aeee026" class="wlWriterPreserve"><script>

var p = document.getElementById('p');

p.onclick = function(e){
alert(e.target.id)
}

</script></span>

<!-----------------------------测试结束-------------------------------------->
</body>
</html>

其实委托的原理都是一样的,通过事件对象过滤出关联目标的hack,做相对应的处理,那么JQuery是如何实现的呢?


jQuery事件的流程图

在绑定阶段与执行阶段


那么JQuery为了更好的对事件的支持内部又做了哪些额外的优化操作?

兼容性问题处理:

浏览器的事件兼容性是一个令人头疼的问题。IE的event在是在全局的window下, 而mozilla的event是事件源参数传入到回调函数中。还有很多的事件处理方式也一样

JQuery提供了一个 event的兼容类方案

jQuery.event.fix 对游览器的差异性进行包装处理

例如:

  1. 事件对象的获取兼容,IE的event在是在全局的window,标准的是event是事件源参数传入到回调函数中
  2. 目标对象的获取兼容,IE中采用srcElement,标准是target
  3. relatedTarget只是对于mouseout、mouseover有用。在IE中分成了to和from两个Target变量,在mozilla中 没有分开。为了保证兼容,采用relatedTarget统一起来
  4. event的坐标位置兼容
  5. 等等

事件的存储优化:

jQuery并没有将事件处理函数直接绑定到DOM元素上,而是通过$.data存储在缓存$.cahce上,这里就是之前分析的贯穿整个体系的缓存系统了

声明绑定的时候:

  • 首先为DOM元素分配一个唯一ID,绑定的事件存储在$.cahce[ 唯一ID ][ $.expand ][ 'events' ]上,而events是个键-值映射对象,键就是事件类型,对应的值就是由事件处理函数组成的数组,最后在DOM元素上绑定(addEventListener/ attachEvent)一个事件处理函数eventHandle,这个过程由 jQuery.event.add 实现。

执行绑定的时候:

  • 当事件触发时eventHandle被执行,eventHandle再去$.cache中寻找曾经绑定的事件处理函数并执行,这个过程由 jQuery.event. trigger 和 jQuery.event.handle实现。
  • 事件的销毁则由jQuery.event.remove 实现,remove对缓存$.cahce中存储的事件数组进行销毁,当缓存中的事件全部销毁时,调用removeEventListener/ detachEvent销毁绑定在DOM元素上的事件处理函数eventHandle。

事件处理器:

jQuery.event.handlers

针对事件委托和原生事件(例如"click")绑定 区分对待

事件委托从队列头部推入,而普通事件绑定从尾部推入,通过记录delegateCount来划分,委托(delegate)绑定和普通绑定。

其余一些兼容事件的Hooks

fixHooks,keyHooks,mouseHooks


总的来说对于JQuery的事件绑定

在绑定的时候做了包装处理

在执行的时候有过滤器处理

下章就开始深入on内部实现的分析了

jQuery 2.0.3 源码分析 事件体系结构的更多相关文章

  1. jQuery 2.0.3 源码分析 事件绑定 - bind/live/delegate/on

    事件(Event)是JavaScript应用跳动的心脏,通过使用JavaScript ,你可以监听特定事件的发生,并规定让某些事件发生以对这些事件做出响应 事件的基础就不重复讲解了,本来是定位源码分析 ...

  2. jQuery 2.0.3 源码分析Sizzle引擎解析原理

    jQuery 2.0.3 源码分析Sizzle引擎 - 解析原理 声明:本文为原创文章,如需转载,请注明来源并保留原文链接Aaron,谢谢! 先来回答博友的提问: 如何解析 div > p + ...

  3. Spark2.1.0之源码分析——事件总线

    阅读提示:阅读本文前,最好先阅读<Spark2.1.0之源码分析——事件总线>.<Spark2.1.0事件总线分析——ListenerBus的继承体系>及<Spark2. ...

  4. jQuery 2.0.3 源码分析 Deferred(最细的实现剖析,带图)

    Deferred的概念请看第一篇 http://www.cnblogs.com/aaronjs/p/3348569.html ******************构建Deferred对象时候的流程图* ...

  5. jQuery 2.0.3 源码分析 Deferred概念

    JavaScript编程几乎总是伴随着异步操作,传统的异步操作会在操作完成之后,使用回调函数传回结果,而回调函数中则包含了后续的工作.这也是造成异步编程困难的主要原因:我们一直习惯于“线性”地编写代码 ...

  6. jQuery 2.0.3 源码分析 Deferrred概念

    转载http://www.cnblogs.com/aaronjs/p/3348569.html JavaScript编程几乎总是伴随着异步操作,传统的异步操作会在操作完成之后,使用回调函数传回结果,而 ...

  7. jQuery 2.0.3 源码分析core - 选择器

         声明:本文为原创文章,如需转载,请注明来源并保留原文链接Aaron,谢谢!      打开jQuery源码,一眼看去到处都充斥着正则表达式,jQuery框架的基础就是查询了,查询文档元素对象 ...

  8. jQuery 2.0.3 源码分析core - 整体架构

    拜读一个开源框架,最想学到的就是设计的思想和实现的技巧. 废话不多说,jquery这么多年了分析都写烂了,老早以前就拜读过, 不过这几年都是做移动端,一直御用zepto, 最近抽出点时间把jquery ...

  9. jQuery 2.0.3 源码分析Sizzle引擎 - 编译函数(大篇幅)

    声明:本文为原创文章,如需转载,请注明来源并保留原文链接Aaron,谢谢! 从Sizzle1.8开始,这是Sizzle的分界线了,引入了编译函数机制 网上基本没有资料细说这个东东的,sizzle引入这 ...

随机推荐

  1. OpenGL入门

    OpenGL是个啥... 网上资料挺多的,今天在codeblocks配置了一下..抄了一会书上的代码,还挺有意思的. 首先,从官网把glut的包给下载下来,点这里. 以下内容从网上抄的: 将glut. ...

  2. dotnetcore 单元测试

    dotnetcore的单元测试目前支持的比较好的是xunit,首先通过nuget添加组件dotnet-test-xunit 和 xunit.如果有依赖注入可在构造方法中,相当于Nunit中的[Setu ...

  3. git上传代码到osc@git

    1.get an account 2.get a ssh-key 3.git setting git config --global user.name "...." git co ...

  4. 实现Myxls设置行高的功能(转)

    MyXLS是一个导出Excel的好工具,速度快,体积小,而且也不用担心使用Com生成Excel时资源释放的问题了.但是作者提供的代码没有设置行高 要实现这个效果,首先需要修改两个文件: 1.Row.c ...

  5. web前端笔试选择题

    1. 要动态改变层中内容可以使用的方法有(AB ) a)innerHTML b)innerText c)通过设置层的隐藏和显示来实现 d)通过设置层的样式属性的display属性 2. 当按键盘A时, ...

  6. java空指针异常:java.lang.NullPointException

    一.什么是java空指针异常 我们都知道java是没有指针的,这里说的"java指针"指的就是java的引用,我们不在这里讨论叫指针究竟合不合适,而只是针对这个异常本身进行分析.空 ...

  7. 游标cursor

    if exists(select * from sys.objects where name='info_one') drop table info_one go create table info_ ...

  8. 客户端用javascript获取文件大小

    客户端用javascript获取文件大小 1 ie实现代码如下: <script type="text/javascript" language="javascri ...

  9. mysql外键添加error1215

    在mysql创建表外键的过程中,由于操作不当,会提示cannot add foreign key constraint的错误. 造成此错误可能的原因如下: 1.数据类型不匹配,外键与其相关联的键必须数 ...

  10. git学习笔记一

    一.概念理解 1.理解工作区和暂存区以及版本库 工作区我理解就是我们创建的程序所在的文件夹,比如test文件夹.其中有个.git文件,这个就是版本库,其中版本库中有个区域叫暂存区或叫索引. 截自廖雪峰 ...