事件冒泡与事件捕获区别

悟透事件捕获和冒泡

对“捕获”和“冒泡”这两个概念,我想我们对冒泡更熟悉一些,因为在我们使用的所有浏览器中,都支持事件冒泡,即事件由子元素向祖先元素传播的,就像气泡从水底向水面上浮一样。而在像firefox,chrome,safari这类所谓的标准浏览器中,事件传播还有个阶段,那就是捕获阶段,这个很少有用武之地,所以被人疏忽遗忘也在所难免了,不常用不代表它不存在,本着科学严谨的态度,我们有必要去看一下它的庐山真面目。

事实上,捕获阶段是一个和冒泡阶段完全相反的过程,即事件由祖先元素向子元素传播,和一个石子儿从水面向水底下沉一样,要说明的是在IE,opera浏览器中,是不存在这个阶段的。从各浏览器提供的注册事件监听的方法中可见一斑,例如适用于ie,opera的attachEvent,有两个参数,attachEvent(”on”+type,fn),而适用于所谓标准浏览器的addEventListener则有三个参数,addEventListener(type,fn,boolean),前面两个参数不用解释,第三个参数boolean,就是决定注册事件发生在捕获阶段还是冒泡阶段,具体参考如下:

  • true : 捕获阶段
  • false : 冒泡阶段

话说,眼见为实,耳听为虚!那么好吧,请看demo,猛击这里

在这个demo中,注册事件监听默认发生在冒泡阶段,由于“元素a”,“元素b”和“元素c”有嵌套关系,为了更好的表现冒泡过程,所以请先点击“元素c”,会看到在各个浏览器中呈现的视觉效果是一致的,即事件是从c向a传播的,这也恰恰证明了所有浏览器都有冒泡这个过程的观点。经过上述的介绍,唯一让你感到吃惊的应该是,从视觉效果上,“元素c”并没有包含在“元素a”和“元素b”里面,而表现出来的效果确实证明”click”事件依次从c经过b传播到a的,反而包含“元素c”的“元素d”却没有响应click事件。事实上,这并不奇怪,因为事件冒泡和视觉上的布局结构是毫无关系的,这个冒泡过程仅仅依赖于dom元素的html结构(即嵌套关系)。效果见下图:

提及事件冒泡,那么不得不提“阻止事件冒泡”这个概念,因为我们最经常处理的任务就在于如何阻止事件的冒泡,来避免一些不必要的麻烦,关于这点,由于在之前的文章中单独讨论过,在此不再赘述,详见:阻止事件冒泡

言归正传,为了更好的看到捕获和冒泡的区别,那么这时候需要你把这个demo另存到本地,然后找到如下图所示的代码片段:

接下来,你要做的就是,把这个代码片段中false改为true,也就是说让注册事件监听在捕获阶段进行,依次ctrl+s,在各个浏览器中打开这个页面,细心的你会发现,在firefox,chrome,safari中表现效果发生了变化(IE,opera中无变化,因为不存在捕获阶段),如下图:

对比两张图片所显示的视觉效果,应该足以证明本文开头所提出的观点了,如果针对事件捕获和冒泡尚有任何疑问或不解,请留言或者Email我,交流研究!

取消事件冒泡

在默认情况下,发生在一个子元素上的单击事件(或者其他事件),如果在其父级元素绑定了一个同样的事件,此时点击子元素,click事件会首先被子元素捕获,执行绑定的事件程序,之后会被父级元素捕获,再次激发一段脚本的执行,这就是所谓的“事件冒泡”。

看个例子:demo1

在通常情况下,我们只希望事件发生在它的目标而并非它的父级元素上,只需加个stopBubble方法,即可取消事件冒泡,代码如下:

  1. function stopBubble(e){
  2.   // 如果传入了事件对象,那么就是非ie浏览器
  3.   if(e&&e.stopPropagation){
  4.     //因此它支持W3C的stopPropagation()方法
  5.     e.stopPropagation();
  6.   }else{
  7.     //否则我们使用ie的方法来取消事件冒泡
  8.     window.event.cancelBubble = true;
  9.   }
  10. }

取消事件冒泡事件后,详见:demo2

现在你可能想知道,什么时候需要阻止事件冒泡?事实上,现在绝大多数情况下都可以不必在意它。但是当你开始开发动态应用程序(尤其是需要处理键盘和鼠标)的时候,就有这个必要了。

你可能感兴趣的:(事件冒泡与事件捕获区别)