细说addEventListener与事件捕获、事件冒泡
(一)addEventListener的基本用法

在复杂的项目开发中,javascript和html的解耦变得至关重要,我们被推荐使用事件动态绑定的方式来处理按钮的事件。W3C为我们提供了addEventListener()函数用来为指定的dom元素动态绑定事件。这个函数有三个参数:
type:用来设置时间类型,例如click
listener:用来设置监听事件的函数,及type类型的事件发生后执行的函数

大部分情况下,确切的说是我们绑定事件的元素的父元素和子元素都不存在操作类型相同的触发事件时,前两个参数就可以满足我们为按钮绑定事件的需求。
比如:

function sayHello() {
    console.log("hello");
}

var myDiv = document.getElementById("myDiv");
myDiv.addEventListener("click", sayHello);

这样我们点击id为myDiv的元素时,控制台就会输出"Hello"。
(二)事件冒泡

但是,当出现如下情况时,情况就变得有些复杂。
下面的html中存在“四世同堂”的个元素(这里我省略了它们的CSS样式)运行效果如图所示

<div id="grandpa" style="...">grandpa
    <div id="father" style="...">father
        <div id="child" style="...">child
            <div id="grandson" style="...">grandson</div>
        </div>
    </div>
</div>

!\[这里写图片描述\](http://img.blog.csdn.net/20160628224521687)
最外层褐色的是id为grandpa的div,其后粉色的是id为father的div,蓝色的是id为child的div,最里层黑色的是id为grandson的div。(子元素依次置于父元素之中且逐级变小)
下面设置了四个函数用来进行事件绑定:

function sleep() {
        console.log("grandpa: I am sleeping,well I just can't fall asleep");
    }

function watchTV() {
        console.log("father:I am watching TV");
    }

function playingCard() {
        console.log("child:I am playing Card");
    }

function doingHomework() {
        console.log("grandson:I am doing my homework T_T");
    }

使用下面的代码,我们可以获取四个元素对应DOM

var grandpa = document.getElementById("grandpa");
   var father = document.getElementById("father");
   var child = document.getElementById("child");
   var grandson = document.getElementById("grandson");

现在,我试着同时分别为grandpa和grandson绑定sleep和doingHomework事件。

grandpa.addEventListener("click", sleep);
  grandson.addEventListener("click", doingHomework);

这时我们点击最外层的grandpa时,当然会触发sleep函数,然而当我们点击grandson时,控制台的输出如下:
![这里写图片描述](图片描述
这是因为grandson在grandpa之上,当点击grandson时,同时也在grandpa上进行了点击操作,所以在执行了doingHomework后,还会触发grandpa的sleep函数。
这种当满足条件后从子元素到父元素依次触发其上事件的处理方式叫做事件冒泡
我们也为father和child分别绑定watchTV和playingCard函数

father.addEventListener("click", watchTV);
    child.addEventListener("click", playingCard);

这时当点击grandson时,由于事件冒泡原理,显然,先触发doingHomework,再执行playingCard,再执行watchTV,最后执行grandpa的sleep。
(三)事件捕获

JS还设置了另外一种处理多(父子)元素多事件触发的方式,叫做事件捕获。事件捕获与事件冒泡完全相反,先触发祖先元素的事件,然后再逐级触发子元素的事件。默认情况下,绑定事件时,采用事件冒泡原则,如果想要进行事件捕获的话,需要设置一个参数。
(四)addEventListener神秘的第三个参数

我们可以为addEventListener函数添加第三个参数useCapture,参数值是布尔值,默认是false。当useCapture为false时,事件处理采取事件冒泡的原则,当userCapture为true时,则采取事件捕获的原则,现在我们为我们“四世同堂”的元素设置第三个参数。

grandpa.addEventListener("click", sleep, true);
   father.addEventListener("click", watchTV, true);
   child.addEventListener("click", playingCard, true);
   grandson.addEventListener("click", doingHomework, true);

这时,当点击grandson时,就会先执行祖先元素的事件,再执行后代元素的事件了,控制台的输出如下图所示:
这里写图片描述
虽然默认情况下,useCapture的值是false,但我推荐我们在绑定函数时把它明显的写出来以避免浏览器兼容性的问题。
(五)事件冒泡与事件捕获要是同时进行怎么办

有思想的同学肯定会思考这样一个问题,在上述绑定事件的代码中,第三个参数不是全部设置的true,就是全部设置成false,那如果既有true,又有false,有的元素设置成按事件冒泡处理,有的元素设置成按事件捕获处理,那怎么办呢?
这里就不调大家的性子了,直接告诉大家答案,我们的浏览器更“喜爱”事件捕获:它会先把useCapture为false的元素绑定事件放到一边,按照事件捕获正常的顺序执行useCapture为true的元素绑定事件,最后在按照事件冒泡顺序执行useCapture为false。
现在我们作如下更改

grandpa.addEventListener("click", sleep, true);
    father.addEventListener("click", watchTV, false);
    child.addEventListener("click", playingCard, true);
    grandson.addEventListener("click", doingHomework, false);

按照上述原则,当点击grandson时,先执行useCapture为true的元素的绑定事件,又按照事件捕获原则,先执行grandpa的事件,再执行child的事件。之后,再按照事件捕获顺序执行useCapture为false的事件,输出结果如下:
这里写图片描述
(六)阻止事件冒泡和捕获

我们可以利用时间对象event的stopPropagation()方法组织事件的进一步传播。
我们修改一下doingHomework函数:

function doingHomework(event) {

// 阻止事件的进一步传播,但仍旧会执行接下来的代码
        event.stopPropagation();
        console.log("grandson:I am doing my homework T_T");
    }

这时我们点击grandson,控制台输出的结果是:
这里写图片描述
发现事件执行到doingHomework就被阻断了。值得注意的是,event.stopPropagation()函数并不会阻止其下函数内容的执行。
如果你使用的是jquery的事件绑定,也可以直接在函数中使用return false来阻止事件的传播(当然event.stopPropagation同样有效),与event.stopPropagation不同的是,return false会阻止同函数下面的代码执行。这里就不举例了。

关于事件的绑定与传播,就介绍到这里,希望对大家有帮助。

By.圣经的旋律

细说addEventListener与事件捕获的更多相关文章

  1. 使用事件捕获实时捕获img是否加载完毕, 实现iframe内容高度自动适应

    如何判断在html中图片加载完毕呢? 给img图片加onload事件呗. 如何判断一个界面中所有的图片加载完毕呢? 给所有的图片加上onload事件呗. 如果有1000张图片那要怎么绑定事件呢? 我们 ...

  2. 事件流之事件冒泡与事件捕获<JavaScript高级程序设计>学习笔记

    1.事件流 浏览器开发团队遇到一个很有意思问题:页面的那一部分会拥有特定的事件? 对于理解这个问题您可以想象画在一张纸上的一组同心圆,如果你把手指放在圆心上,那么你的手指指向的其实不是一个圆,而是纸上 ...

  3. javascript中的事件冒泡、事件捕获和事件执行顺序

    谈起JavaScript的 事件,事件冒泡.事件捕获.阻止默认事件这三个话题,无论是面试还是在平时的工作中,都很难避免. DOM事件标准定义了两种事件流,这两种事件流有着显著的不同并且可能对你的应用有 ...

  4. js之事件冒泡和事件捕获

    (1)冒泡型事件:事件按照从最特定的事件目标到最不特定的事件目标(document对象)的顺序触发. IE 5.5: div -> body -> document IE 6.0: div ...

  5. js之事件冒泡和事件捕获详细介绍

    (1)冒泡型事件:事件按照从最特定的事件目标到最不特定的事件目标(document对象)的顺序触发. IE 5.5: div -> body -> document IE 6.0: div ...

  6. Javascript 事件对象(五)事件捕获

    事件捕获: <!DOCTYPE HTML> <html> <head> <meta http-equiv="Content-Type" c ...

  7. javascript --- 事件冒泡与事件捕获

    事件冒泡与事件捕获 事件冒泡和事件捕获分别由微软和网景公司提出,这两个概念都是为了解决页面中事件流(事件发生顺序)的问题.考虑下面这段代码,就不写html->head,body之类的代码了,自行 ...

  8. JavaScript高级程序设计笔记 事件冒泡和事件捕获

    1.事件冒泡 要理解事件冒泡,就得先知道事件流.事件流描述的是从页面接收事件的顺序,比如如下的代码: <body> <div> click me! </div> & ...

  9. dom事件不求甚解,色解事件捕获和冒泡

    以前对事件只会用jq的bind绑定一下,脑海里留着书中的事件循环,一直认为事件就是这儿循环的,最近看园子里的文章,对事件的了解更模糊了 所以我做了个小实验,总结一下看的这些零零碎碎的文章,如果总结错了 ...

随机推荐

  1. Openssl的证书操作

    先假设自己是一个CA,而且是一个root CA,Cliu8CA 生成一个CA的private key openssl genrsa -out caprivate.key 1024 当然可以跟密码 op ...

  2. 算法与数据结构(六) 迪杰斯特拉算法的最短路径(Swift版)

    上篇博客我们详细的介绍了两种经典的最小生成树的算法,本篇博客我们就来详细的讲一下最短路径的经典算法----迪杰斯特拉算法.首先我们先聊一下什么是最短路径,这个还是比较好理解的.比如我要从北京到济南,而 ...

  3. 【开源项目】电视盒子好用又强大的APP: TVRemoteIME

    TVRemoteIME 电视盒子的远程输入法应用,可跨屏远程输入.跨屏远程控制盒子.远程文件管理.HTTP/RTMP/MMS网络视频直播.ED2K/种子文件的视频文件边下边播 应用的诞生 自从家里有电 ...

  4. React Native组件、生命周期及属性传值props详解

    创建组件的三种方式 第一种:通过ES6的方式创建 /** * 方式一 :ES6 */ export default class HelloComponent extends Component { r ...

  5. Javascript高级编程学习笔记(85)—— Canvas(2)2D上下文

    2D上下文 使用2D上下文提供的方法可以绘制简单的2D图形,如矩形,弧线和路径; 2D上下文的坐标开始域<canvas>元素的左上角,原点坐标为(0,0) 后续所有操作的计算都基于原点,x ...

  6. [Swift]LeetCode161. 一次编辑距离 $ One Edit Distance

    Given two strings S and T, determine if they are both one edit distance apart. 给定两个字符串S和T,确定它们是否都是是一 ...

  7. [Swift]LeetCode298. 二叉树最长连续序列 $ Binary Tree Longest Consecutive Sequence

    Given a binary tree, find the length of the longest consecutive sequence path. The path refers to an ...

  8. Spring Boot: Yaml配置文件 以及 @ConfigurationProperties属性获取

    Yaml配置文件 概述 Spring Boot在支持application.properties配置文件的同时,也支持application.yaml配置文件. 配置文件中的属性,可以通过: 通过@V ...

  9. 『Raid 平面最近点对』

    平面最近点对 平面最近点对算是一个经典的问题了,虽然谈不上是什么专门的算法,但是拿出问题模型好好分析一个是有必要的. 给定\(n\)个二元组\((x,y)\),代表同一平面内的\(n\)个点的坐标,求 ...

  10. Android--从系统Gallery获取图片

    前言 在Android应用中,经常有场景会需要使用到设备上存储的图片,而直接从路径中获取无疑是非常不便利的.所以一般推荐调用系统的Gallery应用,选择图片,然后使用它.本篇博客将讲解如何在Andr ...