浅谈事件冒泡与事件捕获

标签: javascript 事件代理 前端 | 发表时间:2014-10-30 20:00 | 作者:ac黄
出处:http://segmentfault.com/blogs

事件冒泡与事件捕获

事件冒泡和事件捕获分别由微软和网景公司提出,这两个概念都是为了解决页面中 事件流(事件发生顺序)的问题。

  <div id="outer">
    <p id="inner">Click me!</p>
</div>

上面的代码当中一个div元素当中有一个p子元素,如果两个元素都有一个click的处理函数,那么我们怎么才能知道哪一个函数会首先被触发呢?

为了解决这个问题微软和网景提出了两种几乎完全相反的概念。

事件冒泡

微软提出了名为 事件冒泡(event bubbling)的事件流。事件冒泡可以形象地比喻为把一颗石头投入水中,泡泡会一直从水底冒出水面。也就是说,事件会从最内层的元素开始发生,一直向上传播,直到document对象。

因此上面的例子在事件冒泡的概念下发生click事件的顺序应该是 p -> div -> body -> html -> document

事件捕获

网景提出另一种事件流名为 事件捕获(event capturing)。与事件冒泡相反,事件会从最外层开始发生,直到最具体的元素。

上面的例子在事件捕获的概念下发生click事件的顺序应该是 document -> html -> body -> div -> p

addEventListener的第三个参数

“DOM2级事件”中规定的事件流同时支持了事件捕获阶段和事件冒泡阶段,而作为开发者,我们可以选择事件处理函数在哪一个阶段被调用。

addEventListener方法用来为一个特定的元素绑定一个事件处理函数,是JavaScript中的常用方法。addEventListener有三个参数:

element.addEventListener(event, function, useCapture)

第一个参数是需要绑定的事件,第二个参数是触发事件后要执行的函数。而第三个参数默认值是false,表示在事件冒泡的阶段调用事件处理函数,如果参数为true,则表示在事件捕获阶段调用处理函数。请看 例子

事件代理

在实际的开发当中,利用事件流的特性,我们可以使用一种叫做事件代理的方法。

  <ul id="color-list">
    <li>red</li>
    <li>yellow</li>
    <li>blue</li>
    <li>green</li>
    <li>black</li>
    <li>white</li>
</ul>

如果点击页面中的li元素,然后输出li当中的颜色,我们通常会这样写:

  (function(){
    var color_list = document.getElementById('color-list');
    var colors = color_list.getElementsByTagName('li');
    for(var i=0;i<colors.length;i++){                          colors[i].addEventListener('click',showColor,false);
    };
    function showColor(e){
        var x = e.target;
        alert("The color is " + x.innerHTML);
    };
})();

利用事件流的特性,我们只绑定一个事件处理函数也可以完成:

  (function(){
    var color_list = document.getElementById('color-list');
    color_list.addEventListener('click',showColor,false);
    function showColor(e){
        var x = e.target;
        if(x.nodeName.toLowerCase() === 'li'){
            alert('The color is ' + x.innerHTML);
        }
    }
})();

使用事件代理的好处不仅在于将多个事件处理函数减为一个,而且对于不同的元素可以有不同的处理方法。假如上述列表元素当中添加了其他的元素(如:a、span等),我们不必再一次循环给每一个元素绑定事件,直接修改事件代理的事件处理函数即可。

冒泡还是捕获?

对于事件代理来说,在事件捕获或者事件冒泡阶段处理并没有明显的优劣之分,但是由于事件冒泡的事件流模型被所有主流的浏览器兼容,从兼容性角度来说还是建议大家使用事件冒泡模型。

IE浏览器兼容

IE浏览器对addEventListener兼容性并不算太好,只有IE9以上可以使用。

addEventListener兼容性

要兼容旧版本的IE浏览器,可以使用IE的attachEvent函数

object.attachEvent(event, function)

两个参数与addEventListener相似,分别是事件和处理函数,默认是事件冒泡阶段调用处理函数,要注意的是,写事件名时候要加上"on"前缀("onload"、"onclick"等)。

感谢您的阅读,有不足之处请为我指出。

参考

  1. HTML DOM addEventListener() Method -- w3schools
  2. JavaScript高级程序设计(第3版)
  3. attachEvent method -- MSDN
  4. What is event bubbling and capturing -- Stack Overflow

文章同步在我的博客,本文链接: http://acwong.org/2014/10/28/bubbling-and-capturing/

相关 [事件 事件] 推荐:

backbone 之事件(events)

- - 博客园_首页
  最近用 backbone 做了一个项目,加深了对前端mvc理解. 一定要应用的熟练后,了解其思想后,再去阅读源码. 想写写自己对backbone的感悟. 接下来第一步就是backbone的event.   backbone的event 是其核心.  当我们user调用create 就会触发change事件.

测试touch事件

- - Kejun's Blog
进入触屏时代意味一切要对触屏友好. 今天仅仅测试了ios6,其它版本包括android还不清楚差别有多大. 看了PPK的touch兼容表(http://www.quirksmode.org/mobile/tableTouch.html),深感刚准备告别ie6,又迎来了一个新的混乱时代,苦逼的前端工程师们永远摆脱不了兼容的魔咒.

Jquery手动触发事件

- - 博客园_首页
    废话不多说,直接贴代码:.     如果想触发一个id为input的文本框的blur事件,则可以这样写:.     相类似,如果想调用input的click事件,则可以这样写:.

js中的事件委托

- - JavaScript - Web前端 - ITeye博客
1,什么是事件委托:通俗的讲,事件就是onclick,onmouseover,onmouseout,等就是事件,委托呢,就是让别人来做,这个事件本来是加在某些元素上的,然而你却加到别人身上来做,完成这个事件. 也就是:利用冒泡的原理,把事件加到父级上,触发执行效果. 我们可以看一个例子:需要触发每个li来改变他们的背景颜色.

JavaScript与HTML交互——事件

- - 博客园_首页
JavaScript和HTML的交互是通过事件实现的. JavaScript采用异步事件驱动编程模型,当文档、浏览器、元素或与之相关对象发生特定事情时,浏览器会产生事件. 如果JavaScript关注特定类型事件,那么它可以注册当这类事件发生时要调用的句柄. 事件流描述的是从页面中接收事件的顺序,比如有两个嵌套的div,点击了内层的div,这时候是内层的div先出发click事件还是外层先触发.

jQuery事件编写进阶

- - 阿里巴巴(中国站)用户体验设计部博客
jQuery 事件编程进阶. 事件委托,是一种优化DOM元素事件绑定的技巧,利用事件冒泡的原理,通过绑定事件到父元素,检查event触发元素的target,最终执行相应的事件函数处理,它的几个好处一般前端开发程序员都知道. 在jQuery中,一般是delegate()方法和.live()方法,但是,如何选择事件委托的方法,或者在什么情况下用.live(),什么情况下用.delegate(),这个值得讲一讲:.

JS动态添加事件

- - CSDN博客推荐文章
方法一、setAttribute. obj.setAttribute("onclick", "javascript:alert('测试');");. 但是IE不支持用 setAttribute 设置某些属性,包括对象属性、集合属性、 事件属性,也就是说用 setAttribute 设置 style、onclick、onmouseover 这些属性在 IE 中是行不通的.

Redis事件综合分析

- - FreeBuf.COM | 关注黑客与极客
redis未授权访问一直未被大家重视,直到11月4号,在. 这篇blog 上被爆出:redis可以通过写入SSH Key进而控制服务器,安全人员开始大量关注这一事件. 暴露在公网的redis如果没有启用认证服务或者采用弱口令密钥对时,可被攻击者恶意登录,通过写入SSH公钥或者写入crontab执行命令的方式进而控制服务器.

细说dom就绪事件

- - 崔永键的博客
OK,现在来谈谈DOM就绪事件. 这个问题,关系到浏览器内核实现,但我们作为前端,能力不及. 便从表象上去理解它,进而推断出对前端开发有所帮助的实践方案,就够了. OK,浏览器DOM加载顺序是什么样的呢. 可以参考IBM的一篇文章:http://www.ibm.com/developerworks/cn/web/1308_caiys_jsload/.

Spring事件监听原理

- - 掘金 后端
基于 SpringBoot-3.1.2. Spring 事件机制主要用于业务编码的解耦,例如用户订单办理成功,需要发送短信通知,这是两个不同的业务逻辑,不应该耦合在一起,针对于此,就可以通过事件机制来解决,以下是一个最简单的Spring事件使用示例. 准备事件监听器(也就是发布事件后,对应的处理者).