虽然精通jquery,但对它的原型javascript却不是很了解,最近在学习javascript中遇到了一些困难,比如冒泡和捕获,很多次被提到,但又不知究竟应用在何处。找到了一些好文章解惑,在这里分享给大家
 

一、事件的发生顺序

这个问题的起源非常简单,假设你在一个元素中又嵌套了另一个元素

复制代码代码如下:
-----------------------------------
| element1                        |
|   -------------------------     |
|   |element2               |     |
|   -------------------------     |
|                                 |
-----------------------------------

:并且两者都有一个onClick事件处理函数(event handler)。如果用户单击元素2,则元素1和元素2的单击事件都会被触发。但是哪一个事件先被触发?哪一个事件处理函数会被首先执行?换句话说,事件的发生顺序到底如何?

二、两种模型

不出所料,在那些“不堪回首”(浏览器大战)的日子里,Netscape和微软有两种截然不同的处理方法:

Netscape主张元素1的事件首先发生,这种事件发生顺序被称为捕获型
微软则保持元素2具有优先权,这种事件顺序被称为冒泡型
这两种事件顺序是截然相反的。Explorer浏览器只支持冒泡事件,Mozilla,Opera7和Konqueror两者都支持。而更古老的opera和iCab两者都不支持

三、捕获型事件

当你使用捕获型事件时

复制代码代码如下:
               | |
---------------| |-----------------
| element1     | |                |
|   -----------| |-----------     |
|   |element2  \ /          |     |
|   -------------------------     |
|        Event CAPTURING          |
-----------------------------------

:元素1的事件处理函数首先被触发,元素2的事件处理函数最后被触发

四、冒泡型事件

当你使用冒泡型事件时

复制代码代码如下:
               / \
---------------| |-----------------
| element1     | |                |
|   -----------| |-----------     |
|   |element2  | |          |     |
|   -------------------------     |
|        Event BUBBLING           |
-----------------------------------

:元素2 的处理函数首先被触发,元素1其次

五、W3C 模型

W3c明智的在这场争斗中选择了一个择中的方案。任何发生在w3c事件模型中的事件,首是进入捕获阶段,直到达到目标元素,再进入冒泡阶段

复制代码代码如下:
                 | |  / \
-----------------| |--| |-----------------
| element1       | |  | |                |
|   -------------| |--| |-----------     |
|   |element2    \ /  | |          |     |
|   --------------------------------     |
|        W3C event model                 |
------------------------------------------

为一个web开发者,你可以选择是在捕获阶段还是冒泡阶段绑定事件处理函数,这是通过addEventListener()方法实现的,如果这个函数的最后一个参数是true,则在捕获阶段绑定函数,反之false,在冒泡阶段绑定函数。

假设你要做

复制代码代码如下:
element1.addEventListener('click',doSomething2,true)

element2.addEventListener('click',doSomething,false)

如果用户单击元素2,则接下来会发生:

(事件在这里就像一个观光客,由外至内游览,逐渐接近被触发的主要元素,然后又反向离开)

1.单击事件首先进入捕获阶段开始(逐渐接近元素2的方向)。查看元素2的祖先元素中是否有在捕获阶段有onclick处理函数的
2.发现元素1有一个,于是doSomething2被执行
3.事件检查到目标自己(元素2),捕获阶段没有发现更多的处理函数了。事件开始进入冒泡阶段,想当然执行doSomething(),这个绑定于元素2冒泡阶段的函数。
4.事件向远离元素2的方向,查看是否有任何祖先元素在冒泡阶段绑定了一个处理函数。没有这样的情况,所以什么也没有发生
相反的情况是:

复制代码代码如下:
element1.addEventListener('click',doSomething2,false)

element2.addEventListener('click',doSomething,false)

现在如果用户点击元素2会发生:

1.单击事件进入捕获阶段。查看元素2的祖先元素中是否有在捕获阶段有onclick处理函数的,结果一无所获
2.事件检查到目标自己。事件开始进入冒泡阶段,并且执行绑定于元素2冒泡阶段的函数。doSomething()
3.事件开始远离目标,检查元素2的祖先元素中是否有在冒泡阶段绑定了处理函数的
4.发现了一个,于是元素1的doSomething2()被执行

六、兼容性和传统模式

在支持w3c dom(文档对象模型) 的浏览器中,传统的事件绑定方法是

复制代码代码如下:
element1.onclick = doSomething2;

默认被视为在绑定于冒泡阶段

七、使用冒泡型事件

很少的开发人员会有意识的去使用冒泡型事件或者捕获型事件。在他们今天制作的网页中,没有必要让一个事件因为冒泡而被好几个函数处理。但是有时用户通常会很疑惑,因为在他们只点击了一次鼠标之后出现了许多种情况(多个函数被执行,因为冒泡)。而大多数情况下你还是希望你的处理函数相互独立的。当用户点击了某一个元素,发生什么,点击另一个元素,又对应发生些什么,相互独立,而不因为冒泡连锁。

八、一直在发生

首先你要明白的是事件捕获或者冒泡一直在发生。如果你给整个页面文档的定义一个通用onclick处理函数

复制代码代码如下:
document.onclick = doSomething;
if (document.captureEvents) document.captureEvents(Event.CLICK);

在页面上单击任何元素的单击事件,最终会冒泡至页面最高文档层,因此触发那个通用的处理函数,除非之前一个处理函数明确的指出终止冒泡,这样才冒泡才不会传播到整个文档层面

对上面代码第二句的补充:

>>>先说IE
object.setCapture() 当一个object的被 setCapture 后,他的方法将会被继承到整个文档进行捕获。
当不需要把方法继承到整个文档捕获时,要用 object.releaseCapture()
>>>others
Mozilla 也有类似的功能,方法稍微不同 
window.captureEvents(Event.eventType) 
window.releaseEvents(Event.eventType)
>>>example

复制代码代码如下:
//如果只有下面这句话,那只有点击obj是才会触发click    obj.onclick = function(){alert("something")}
//若加上下面这句话,则方法会被继承到document(或者window,不同浏览器不同)来捕获
obj.captureEvents(Event.click); //FF
obj.setCapture()  //IE

九、用法

因为任何事件传播终止于页面文档(这个最高层),这使默认的事件处理函数变得可能,假设你有这样一个页面

复制代码代码如下:
------------------------------------
| document                         |
|   ---------------  ------------  |
|   | element1    |  | element2 |  |
|   ---------------  ------------  |
|                                  |
------------------------------------
element1.onclick = doSomething;
element2.onclick = doSomething;
document.onclick = defaultFunction;

现在如果用户单击元素1或者元素2,doSomething()将被执行。如果你愿意的话,如果你不想让事件冒泡至执行defaultFunction(),你可以在这里阻止事件冒泡向上传播,。但是如果用户点击页面上的其他部位,defaultFunction()还是会被执行。这样的效果或许有时能用的上。

设置页面­——使处理函数有范围较大的触发面积,在“拖拽效果”脚本中是必须的。一般来说在某一个元素层上发生 mousedown事件意味着选择了这个元素,并且使它能够响应mousemove事件。虽然mousedown通常绑定于这个元素层上以避免浏览器bug,但是其他两者的事件函数的范围必须是整个页面(?)

记住浏览器学的第一法则(First Law of Browserology)是:一切皆有可能(anything can happen),并且是在你起码有点准备的时候。所以有可能发生的是,用户拖拽时,大幅度在页面上移动他的鼠标,脚本却不能在大幅度中做出反应,以至于鼠标也就不再停留在元素层上了

1.如果onmouseover处理函数绑定在元素层上,这个元素层不会再对鼠标的移动有任何反应,这会让用户觉得奇怪
2.如果onmouseup处理函数绑定在元素层上,事件也不能被触发,后果是,用户想放下这个元素层后,元素层持续对鼠标移动做出反应。这会引起(用户)更多的迷惑(?)

所以在这个例子中,事件冒泡非常的有用,因为将你的处理函数放在页面层能保证他们一直能被执行

十、把它给关了(阻止事件冒泡)

但是一般情况下,你会想关了所有的冒泡和捕获以保证函数之间不会打扰到对方。除此之外,如果你的文档结构相当的复杂(许多table之间相互嵌套或者诸如此类),你也会为了节省系统资源,而关闭冒泡。此时浏览器不得不检查目标元素的每一个祖先,看是否它有一个处理函数。即使一个都没有找到,刚刚的搜索同样花费不少时间

在微软的模型中,你必须设置事件的cancelBubble的属性为true

复制代码代码如下:
window.event.cancelBubble = true

在w3c模型中你必须调用事件的stopPropagation()方法

复制代码代码如下:
e.stopPropagation()

这会阻止所有冒泡向外传播。而作为跨浏览器解决方案应该这么作:

复制代码代码如下:
function doSomething(e)

{
      if (!e) var e = window.event;

e.cancelBubble = true;

if (e.stopPropagation) e.stopPropagation();

}

在支持cancelBubble属性的浏览器中设置cancelBubble无伤大雅。浏览器会耸一耸肩然后创造一个这个属性。当然这也并不能真正的取消冒泡,但至少能保证这条命令是安全正确的

十一、currentTarget

像我们之前看到的一样,一个事件用target或者是srcElement属性用来表示事件究竟发生在哪个目标元素上(即用户最初点击的元素)。在我们的例子中是元素2,因为我们单击了它。

非常重要的是,要明白在捕获或者冒泡阶段的目标元素是不变的,它始终与元素2相关联。

但是假设我们绑定了以下函数

复制代码代码如下:
element1.onclick = doSomething;

element2.onclick = doSomething;

如果用户单击元素2, doSomething()会被执行两次。但是你怎么知道哪个html元素正在响应这个事件?target/srcElement也没有给出线索,但人们总是更倾向于元素2,因为它是引起事件的原因(因为用户点击的是它)。
为了解决这个问题,w3c 增加了currentTarget这个属性,它就指向正在处理事件的元素:这恰是我们需要的。很不幸的是微软模型中并没有相似的属性
你也可以使用”this”关键字。在上面的例子中,它相当于正在处理事件的html元素,就像currentTarget。

十二、微软模型的问题

但是当你使用微软事件绑定模型时,this关键字并不相当于HTML元素。联想缺少类似currentTarget属性的微软模型(?)——按上面的代码操作的话,你这么做便意味着:

复制代码代码如下:
element1.attachEvent('onclick',doSomething)

element2.attachEvent('onclick',doSomething)

你无法确切知道哪一个HTML元素正在负责处理事件,这是微软事件绑定模型最严重的问题,对我来说,这也是我从不使用它的原因,哪怕是在开发仅供Windows下的IE的应用程序

我希望能够尽快增加currentTarget类似的属性——或者遵循标准?web开发者们需要这些信息

js之事件冒泡和事件捕获及其阻止详细介绍的更多相关文章

  1. JS事件(事件冒泡和事件捕获)

    事件流:描述的是在页面中接收事件的顺序 事件冒泡:由最具体的元素接收,然后逐级向上传播至最不具体的元素的节点(文档) 事件捕获:最不具体的节点先接收事件,而最具体的节点应该是最后接收事件 DOM中:用 ...

  2. js进阶 12-2 彻底弄懂JS的事件冒泡和事件捕获

    js进阶 12-2 彻底弄懂JS的事件冒泡和事件捕获 一.总结 一句话总结:他们是描述事件触发时序问题的术语.事件捕获指的是从document到触发事件的那个节点,即自上而下的去触发事件.相反的,事件 ...

  3. JS事件冒泡与事件捕获怎么理解?

    在js中存在事件冒泡与事件捕获两种概念,这两个概念都是为了解决页面中事件流(事件发生顺序)的问题. 事件冒泡(dubbed bubbling) 事件冒泡我们从字面意思理解就是当用户行为触发我们页面的定 ...

  4. JS中的事件绑定,事件捕获,事件冒泡以及事件委托,兼容IE

    转载请注明出处:http://www.cnblogs.com/zhangmingze/p/4864367.html   ● 事件分为三个阶段:   事件捕获 -->  事件目标 -->   ...

  5. js 事件冒泡和事件捕获

    事件流:指的是网页中元素接受事件的顺序,它是一个概念,而不是具体的实际的东西 事件冒泡:指的是内层元素的事件,会触发包含着此元素的外层元素的事件,触发的顺序是:由内而外的 例如: <!DOCTY ...

  6. 彻底弄懂JS的事件冒泡和事件捕获

      先上结论:在事件执行流中有两种执行方式.一种是事件冒泡(即事件的执行顺序是从下往上执行的) ;  另一种是捕获(即事件的执行顺序是从上往下执行的); 阻止事件冒泡:   return false; ...

  7. js高级:event,事件冒泡,事件捕获

    1.事件 浏览器客户端上客户触发的行为都称为事件 所有的事件都是天生自带的,不需要我们去绑定,只需要我们去触发. 通过 obj.事件名=function(){} 事件名:onmouseover 鼠标悬 ...

  8. JS高级:事件冒泡和事件捕获;

    1.事件:浏览器客户端上客户触发的行为成为时事件:所有的事件都是天生自带的,不需要我们去绑定,只需要我们去触发 当用户触发一个事件时,浏览器的所有详细信息都存在一个叫做event的对象上,我们把它叫做 ...

  9. 彻底弄懂JS的事件冒泡和事件捕获(不推荐阅读)

    由于搬去敌台了,好久没来博客园,今天无意中翻到有“误认子弟”的评论,这里特意做个说明. 本文中关于事件冒泡和事件捕获的描述和例子都是OK的,错就错在后面用jquery去展示了利用事件冒泡的例子有误,其 ...

随机推荐

  1. 深入理解JAVA虚拟机阅读笔记4——虚拟机类加载机制

    虚拟机把描述类的Class文件加载到内存,并对数据进行校验.转换解析和初始化,最终形成可以被虚拟机直接使用的Java类型,这就是虚拟机的类加载机制. 在Java语言中,类型的加载.连接和初始化过程都是 ...

  2. python的N个小功能(图片预处理:打开图片,滤波器,增强,灰度图转换,去噪,二值化,切割,保存)

    ############################################################################################# ###### ...

  3. iOS 数据库sqlite完整增删改查操作

    1: 创建数据库表格 1.1 — 表格创建使用一个数据库软件快速创建:软件大小14.3M; 下载地址:http://pan.baidu.com/s/1qWOgGoc; 表格创建-> 打开软件,点 ...

  4. BZOJ3244 NOI2013树的计数(概率期望)

    容易发现的一点是如果确定了每一层有哪些点,树的形态就确定了.问题变为划分bfs序. 考虑怎样划分是合法的.同一层的点在bfs序中出现顺序与dfs序中相同.对于dfs序中相邻两点依次设为x和y,y至多在 ...

  5. 遇到问题----linux-----linux 打开文件数 too many open files 解决方法

    在运行某些命令或者 tomcat等服务器持续运行 一段时间后可能遇到   too many open files. 出现这句提示的原因是程序打开的文件/socket连接数量超过系统设定值. 查看每个用 ...

  6. 如何优雅的将DTO转化成BO

    用于网络传输的对象,我们都认为他们可以当做是DTO对象,DTO为系统与外界交互的模型对象,那么肯定会有一个步骤是将DTO对象转化为BO对象或者是普通的entity对象,让service层去处理. 网上 ...

  7. 解题:NOI 2007 社交网络

    题面 先跑一边Floyd乘法原理统计任意两点间最短路数目,然后再枚举一次按照题意即可求出答案,会写那道JSOI2007就会这个 #include<cstdio> #include<c ...

  8. centos详细安装redis步骤

    1. 从官网(http://redis.io)下载最新稳定版2. 使用命令解压下载的tar包:tar –zxvf redis-3.2.0.tar.gz3. 通过命令cd redis-3.2.0进入源码 ...

  9. 关于表单中Readonly和Disabled

    Readonly和Disabled是用在表单中的两个属性,它们都能够做到使用户不能够更改表单域中的内容.但是它们之间有着微小的差别,总结如下: Readonly只针对input(text / pass ...

  10. for,while,do while

    long i; ;i<;i++) printf( printf("%ld\n",i); ) printf("b\n"); i=; do { printf( ...