jquery源码分析(七)——事件模块 event(二)
上一章节探讨了事件的一些概念,接下来看下jQuery的事件模块。
jQuery对事件的绑定分别有几个API:.bind()/.live()/.delegate()/.on()/click(),
不管是用什么方式绑定,归根到底还是用addEventListener/attachEvent(IE)处理的,正如jQuery的选择器一样不管如何匹配最终还是使用浏览器提供的几个接口处理。
那么现在就有个疑问,事件为什么还要区分那么多不同的处理方案?
这里就要涉及到之前提到的 DOM 事件处理模型了,捕获与冒泡,传统的事件处理给某一元素绑定了一个点击事件,传入一个回调句柄处理。element.addEventListener('click',doSomething,false),对比传统事件来存在这些问题
第一:大量的事件绑定,性能消耗,而且还需要解绑(IE会泄漏);
第二:绑定的元素必须要存在;
第三: 后期生成HTML会没有事件绑定,需要重新绑定
第四: 语法过于繁杂
针对这些问题,因此jQuery引进是采用委托的机制思想来处理。
谈到事件委托来复习下上节提到的事件模型。DOM 有个事件流的特性,也就是说我们在页面上触发节点的时候事件都会上下或者向上传播,称为事件捕捉和事件冒泡。,DOM2.0 模型将事件处理流程分为三个阶段:事件捕获阶段、事件目标阶段、事件起泡阶段
事件传送可以分为3个阶段。
(1)在事件捕捉(Capturing)阶段,事件将沿着DOM树向下转送,目标节点的每一个祖先节点,直至目标节点。例如,若用户单击了一个超链接,则该单击事件将从document节点转送到html元素,body元素以及包含该链接的p元素。在此过程中,浏览器都会检测针对该事件的捕捉事件监听器,并且运行这件事件监听器。
(2)在目标(target)阶段,浏览器在查找到已经指定给目标事件的事件监听器之后,就会运行该事件监听器。目标节点就是触发事件的 DOM 节点。例如,如果用户单击一个超链接,那么该链接就是目标节点(此时的目标节点实际上是超链接内的文本节点)。
(3)在冒泡(Bubbling)阶段,事件将沿着DOM树向上转送,再次逐个访问目标元素的祖先节点到document节点。该过程中的每一步。浏览器都将检测那些不是捕捉事件监听器的事件监听器,并执行它们。
- 换句话说,事件委托就是事件目标自身不处理事件,而是把处理任务委托给其父元素或者祖先元素,甚至根元素(document),如.live()
对于jQuery中提供多个api来绑定事件:不管你用的是(click / bind / delegate)之中哪个方法,最终都是 jQuery 底层都是调用 on 方法来完成最终的事件绑定。因此从某种角度来讲除了在书写的方便程度及习惯上挑选,不如直接都采用 on 方法来的痛快和直接使用.on()方法事件处理程序到当前选定的 jQuery 对象中的元素。
在jQuery 1.11中,.on()方法提供绑定事件处理的所有功能、效果不言而喻了,除了性能的差异,通过委托的事件还能很友好的支持动态绑定,只要 on 的delegate 象是 HTML 页面原有的元素,由于是事件的触发是通过Javascript的事件冒泡机制来监测,所以对于所有子元素(包括后期通过JS生成的元素)所有的事件监听均能有效,且由于不用对多个元素进行事件绑定,能够有效的节省内存的损耗。
说了这么多,jQuery提供了这么多绑定的方法,具体有什么区别我们来了解一下:
(1)、.bind()方法:用于直接附加一个事件处理程序到元素上,处理程序附加到 jQuery 对象中当前选中的元素,所以在 .bind() 绑定事件的时候这些元素必须已经存在,很明显就是直接调用没利用委托机制。
(2)、live()方法:将委托的事件处理程序附加到一个页面的 document 元素,从而简化了在页面上动态添加的内容上事件处理的使用。这和delegate() 方法类似,只是把所有事件都委托到document对象上来处理,增加冒泡处理时间。现在已经摒弃该方法了,不推荐使用。还是用例子说明一下:
$('a').live('click', function() { alert("!")})
jQuery 把 alert 函数绑定到 $(document) 元素上,并使用 ’click’和 ’a’作为参数。任何时候只要有事件冒泡到 document 节点上,它就查看该事件是否是一个 click 事件,以及该事件的目标元素与’a’这一CSS 选择器是否匹配,如果都是的话,则执行函数。由于live缺点太多,这里就不一一赘述了。
(3)、 delegate(): 为了突破单一 .bind() 方法的局限性,实现事件委托,引入了.live()方法。后来,为解决“事件传播链”过长的问题,新版本又支持为 .live() 方法指定上下文对象。而为了解决无谓生成元素集合的问题,之后版本干脆直接引入了一个新方法 .delegate()。
使用 .delegate(),前面的例子可以这样写:
- $('#element).delegate('a', 'click', function() { alert("!!!") });
jQuery 查找(‘#element’),并将click 事件和’a’这一CSS选择器作为参数把 alert 函数绑定到(‘#element)上。
事件监听原理是:任何时候只要有事件冒泡到$(‘#element)上,它就查看该事件事件类型是否是click事件,以及该事件的目标元素(curTarget)是否与CCS选择器相匹配。如果都满足就执行函数。可以注意到,这一过程与.live()类似,但是其把处理程序绑定到具体的元素而非document这一根上,从而大大减少事件传播过程(事件冒泡过程)。
由此可见.delegate() 方法是一个相对完美的解决方案。但在DOM结构简单的情况下,也可以使用.live()。
(4)、on方法:其实 .bind(), .live(), .delegate()都是通过.on()来实现的,.unbind(), .die(), .undelegate()也是一样的都是通过.off()来实现的,该接口只是提供了一种统一绑定事件的方法
- 总得来说,虽然bind/delegate/live这三个方法都能实现DOM节点事件绑定,但是可以用 .on() 来代替上述的 3 种方法
说了这么多,具体使用过程中该用那个方法呢?
下面来总结一下:
- 1. 为DOM中的很多元素绑定相同事件;
- 2. 为DOM中尚不存在的元素绑定事件;
- 3. 用.bind()的代价是非常大的,它会把相同的一个事件处理程序hook到所有匹配的DOM元素上
- 4. 不要再用.live()了,它已经不再被推荐了,而且还有许多问题
- 5. .delegate()会提供很好的方法来提高效率,同时我们可以添加一事件处理方法到动态添加的元素上
- 实际运用中,事件委托机制(基于事件冒泡)仍存在不足之处:
- 1. 并非所有的事件都能冒泡,如load, change, submit, focus, blur
- 2. 加大管理复杂
- 3. 不好模拟用户触发事件
- 4. 如何取舍就看项目实际中运用了。
jquery源码分析(七)——事件模块 event(二)的更多相关文章
- jQuery 源码分析(十七) 事件系统模块 实例方法和便捷方法 详解
实例方法和便捷方法是指jQuery可以直接通过链接操作的方法,是通过调用$.event上的方法(上一节介绍的底层方法)来实现的,常用的如下: on(types,selector,data,fn,one ...
- jQuery 源码分析(十一) 队列模块 Queue详解
队列是常用的数据结构之一,只允许在表的前端(队头)进行删除操作(出队),在表的后端(队尾)进行插入操作(入队).特点是先进先出,最先插入的元素最先被删除. 在jQuery内部,队列模块为动画模块提供基 ...
- 一个普通的 Zepto 源码分析(三) - event 模块
一个普通的 Zepto 源码分析(三) - event 模块 普通的路人,普通地瞧.分析时使用的是目前最新 1.2.0 版本. Zepto 可以由许多模块组成,默认包含的模块有 zepto 核心模块, ...
- 使用react全家桶制作博客后台管理系统 网站PWA升级 移动端常见问题处理 循序渐进学.Net Core Web Api开发系列【4】:前端访问WebApi [Abp 源码分析]四、模块配置 [Abp 源码分析]三、依赖注入
使用react全家桶制作博客后台管理系统 前面的话 笔者在做一个完整的博客上线项目,包括前台.后台.后端接口和服务器配置.本文将详细介绍使用react全家桶制作的博客后台管理系统 概述 该项目是基 ...
- jQuery源码分析系列
声明:本文为原创文章,如需转载,请注明来源并保留原文链接Aaron,谢谢! 版本截止到2013.8.24 jQuery官方发布最新的的2.0.3为准 附上每一章的源码注释分析 :https://git ...
- [转] jQuery源码分析-如何做jQuery源码分析
jQuery源码分析系列(持续更新) jQuery的源码有些晦涩难懂,本文分享一些我看源码的方法,每一个模块我基本按照这样的顺序去学习. 当我读到难度的书或者源码时,会和<如何阅读一本书> ...
- [转]jQuery源码分析系列
文章转自:jQuery源码分析系列-Aaron 版本截止到2013.8.24 jQuery官方发布最新的的2.0.3为准 附上每一章的源码注释分析 :https://github.com/JsAaro ...
- jQuery源码分析系列(转载来源Aaron.)
声明:非本文原创文章,转载来源原文链接Aaron. 版本截止到2013.8.24 jQuery官方发布最新的的2.0.3为准 附上每一章的源码注释分析 :https://github.com/JsAa ...
- jQuery源码分析系列——来自Aaron
jQuery源码分析系列——来自Aaron 转载地址:http://www.cnblogs.com/aaronjs/p/3279314.html 版本截止到2013.8.24 jQuery官方发布最新 ...
随机推荐
- bzoj3332: 旧试题
这题就是最大生成树. 把两个点之间的期望建边排序. 把相同的期望一起做,那么在这个做之前,这些有着相同期望的点两两肯定不连,否则就输出No了. 相同的做完之后,再次for一遍check一下有没有两两之 ...
- 曼哈顿距离(坐标投影距离之和)d(i,j)=|X1-X2|+|Y1-Y2|.
曼哈顿距离(坐标投影距离之和)d(i,j)=|X1-X2|+|Y1-Y2|. 我们可以定义曼哈顿距离的正式意义为L1-距离或城市区块距离,也就是在欧几里德空间的固定直角坐标系上两点所形成的线段对轴产生 ...
- css bug(ie6兼容问题)
二.五大浏览器内核1.trident(MSHTML)(三叉戟:三叉线,三齿鱼叉) Gecko (壁虎) presto(迅速的) webkit(safari内核,Chrome内核原型,他是苹果公司自己的 ...
- node.js的模块引用
1.模块的引用示例 var math = require(‘math’): 在common.js规范中,存在require()方法,这个方法接受模块标识,此引引入一个模块的api ...
- ACM_Mystery
Mystery Time Limit: 2000/1000ms (Java/Others) Problem Description: No Description Input: The first l ...
- 修改docker-toolbox/boot2docker容器镜像
进入虚拟机 vi /var/lib/boot2docker/profile 编辑在EXTRA_ARGS,加入 --registry-mirror=https://pee6w651.mirror.ali ...
- 【转】Linux命令学习手册-split命令
转自:http://blog.chinaunix.net/uid-9525959-id-3054325.html split [OPTION] [INPUT [PREFIX]] [功能]将文件分割成多 ...
- VS开发C语言系列(零)-VS2013写C语言错误汇总
错误代码 error C3861:调用函数前未引用 error C4996:调用不安全的函数 error C2668:重载函数不明确 error C3861:"文件名" 找不到标识 ...
- Android 8.0 启动后台service 出错 IllegalStateException: Not allowed to start service Intent
错误原因: Android 8.0 不再允许后台service直接通过startService方式去启动, 具体行为变更如下: 如果针对 Android 8.0 的应用尝试在不允许其创建后台服务的情况 ...
- oracle for linux服务器磁盘空间不足,通过过期的文件释放磁盘空间
--2013-09-16截取的数据-- 使用df-h命令查看系统磁盘空间 [root@erpdbs PROD]# df -h Filesystem Size Used Avail Use% Mount ...