JavaScript 事件捕获冒泡与捕获详情

目录
  • 一、事件流
    • 1、概念
    • 2、DOM事件流
  • 二、事件委托
    • 1、事件委托的优点
    • 2、事件委托的使用
  • 三、禁止事件冒泡与捕获
  • 四、参考文献

一、事件流

JavaScript中,事件流指的是DOM事件流。

1、概念

事件的传播过程即DOM事件流。
事件对象在 DOM 中的传播过程,被称为“事件流”。
举个例子:开电脑这个事,首先你是不是得先找到你的电脑,然后找到你的开机键,最后用手按下开机键。完成开电脑这个事件。这整个流程叫做事件流。

2、DOM事件流

DOM事件,也是有一个流程的。从事件触发开始到事件响应是有三个阶段。

  • 事件捕获阶段
  • 处于目标阶段
  • 事件冒泡阶段

上面例子中,开电脑这个事件的过程就像JavaScript中的事件流,找开机键这个过程就是 事件捕获 的过程,你找到开机键后,然后用手按开机键,这个选择用手去按的过程就是 处于目标阶段 按下开机按钮,电脑开始开机这也就是 事件的冒泡。 顺序为先捕获再冒泡。

了解了事件源,让我们看看它的三个过程吧!

事件捕获:

注:由于事件捕获不被旧版本浏览器(IE8 及以下)支持,因此实际中通常在冒泡阶段触发事件处理程序。

事件捕获处于事件流的第一步,
DOM事件触发时(被触发DOM事件的这个元素被叫作事件源),浏览器会从根节点开始 由外到内 进行事件传播。即事件从文档的根节点流向目标对象节点。途中经过各个层次的DOM节点,最终到目标节点,完成事件捕获。

目标阶段:

当事件到达目标节点的,事件就进入了目标阶段。事件在目标节点上被触发。
就是事件传播到触发事件的最底层元素上。

事件冒泡:

事件冒泡与事件捕获顺序相反。事件捕获的顺序是从外到内,事件冒泡是从内到外。
当事件传播到了目标阶段后,处于目标阶段的元素就会将接收到的时间向上传播,就是顺着事件捕获的路径,反着传播一次,逐级的向上传播到该元素的祖先元素。直到window对象。

看一个例子,点击 box3 会将 box2 与 box1 的点击事件触发。

<!DOCTYPE html>
<html>

<head>
    <meta charset="UTF-8">
    <title>JavaScript 事件冒泡</title>
</head>
<style type="text/css">
    #box1 { background: blueviolet;}
    #box2 {background: aquamarine;}
    #box3 {background: tomato;}
    div { padding: 40px; margin: auto;}
</style>

<body>
    <div id="box1">
        <div id="box2">
            <div id="box3"></div>
        </div>
    </div>
    <script>
        window.onload = function () {
            const box1 = document.getElementById('box1')
            const box2 = document.getElementById('box2')
            const box3 = document.getElementById('box3')
            box1.onclick = sayBox1;
            box2.onclick = sayBox2;
            box3.onclick = sayBox3;
            function sayBox3() {
                console.log('你点了最里面的box');
            }
            function sayBox2() {
                console.log('你点了最中间的box');
            }
            function sayBox1() {
                console.log('你点了最外面的box');
            }
        }
    </script>
</body>

</html>

这个时候 click 捕获的传播顺序为:
window -> document -> <html> -> <body> -> <div #box1> -> <div #box2> -> <div #box3>
这个时候 click 冒泡的传播顺序为:
<div #box3> -> <div #box2> -> <div #box1> -> <body> -> <html> -> document -> window

现代浏览器都是从 window 对象开始捕获事件的,冒泡最后一站也是 window 对象。而 IE8 及以下浏览器,只会冒泡到 document 对象。
事件冒泡:是由元素的 HTML 结构决定,而不是由元素在页面中的位置决定,所以即便使用定位或浮动使元素脱离父元素的范围,单击元素时,其依然存在冒泡现象。

现在我们知道了事件流的三个阶段后,那我们可以利用这个特性做什么呢?

二、事件委托

设想这样一个场景,当你有一堆的<li>标签在一个<ul>标签下,需要给所有的<li>标签绑定onclick事件,这个问题我们可以用循环解决,但还有没有更简便的方式呢?
我们可以给这些<li>共同的父元素<ul>添加onclick事件,那么里面的任何一个<li>标签触发onclick事件时,都会通过冒泡机制,将onclick事件传播到<ul>上,进行处理。这个行为叫做事件委托, <li>利用事件冒泡将事件委托到<ul>上。
也可以利用事件捕获进行事件委托。用法是一样的,只是顺序反了。

  <ul id="myUl">
    <li>item 1</li>
    <li>item 2</li>
    <li>item 3</li>
    ...
  </ul>

可能还是有点不好理解,简单来说,就是利用事件冒泡,将某个元素上的事件委托给他的父级。

举个生活中的例子,双十一快递到了,需要快递小哥送快递一般是挨家挨户送货上门,这样效率慢,小哥想了个办法,把一个小区的快递都放在小区里面的快递驿站,进行送快递的事件委托,小区的收件人能通过取件码去快递驿站领取到自己的快递。
在这里,快递小哥送快递就是一个事件,收件人就是响应事件的元素,驿站就相当于代理元素,收件人凭着收获码去驿站里面领快递就是事件执行中,代理元素判断当前响应的事件匹配该触发的具体事件。

可是这样做有什么好处呢?

1、事件委托的优点

事件委托有两个好处

  • 减少内存消耗
  • 动态绑定事件

减少内存消耗,优化页面性能

JavaScript中,每个事件处理程序都是对象,是对象就会占用页面内存,内存中的对象越多,页面的性能当然越差,而且DOM的操作是会导致浏览器对页面进行重排和重绘(这个不清楚的话,小伙伴可以了解页面的渲染过程),过多的DOM操作会影响页面的性能。性能优化主要思想之一就是为了最小化的重排和重绘也就是减少DOM操作。

在上面给<li>标签绑定onclick事件的例子中,使用事件委托就可以不用给每一个<li>绑定一个函数,只需要给<ul>绑定一次就可以了,当li的数量很多时,无疑能减少大量的内存消耗,节约效率。

动态绑定事件:

如果子元素不确定或者动态生成,可以通过监听父元素来取代监听子元素。
还是上面在<li>标签绑定onclick事件的例子中, 很多时候我们的这些<li>标签的数量并不是固定的,会根据用户的操作对一些<li>标签进行增删操作。在每次增加或删除标签都要重新对新增或删除元素绑定或解绑对应事件。

可以使用事件委托就可以不用给每一个<li>都要操作一遍,只需要给<ul>绑定一次就可以了,因为事件是绑定在<ul>上的, <li>元素是影响不到<ul>的 ,执行到<li>元素是在真正响应执行事件函数的过程中去匹配的,所以使用事件委托在动态绑定事件的情况下是可以减少很多重复工作的。

我们知道了事件委托的优点,那么该如何使用呢?

2、事件委托的使用

事件委托的使用需要用的addEventListener()方法,事件监听。
方法将指定的监听器注册到调用该函数的对象上,当该对象触发指定的事件时,指定的回调函数就会被执行。

用法:

element.addEventListener(eventType, function, useCapture);
参数 必/选填 描述
eventType 必填 指定事件的类型。
function 必填 指定事件触发后的回调函数。
useCapture 选填 指定事件是在捕获阶段执行还是在冒泡阶段执行。

第三个参数 useCapture 是个布尔类型,默认值为false

  • true - 表示事件在捕获阶段执行执行
  • false- 表示事件在冒泡阶段执行执行

看下面例子:

<!DOCTYPE html>
<html>

<head>
  <meta charset="UTF-8">
  <title>JavaScript 事件委托</title>
</head>

<body>

  <ul>
    <li>item 1</li>
    <li>item 2</li>
    <li>item 3</li>
    <li>item 4</li>
  </ul>

  <script>
    const myUl = document.getElementsByTagName("ul")[0];

    myUl.addEventListener("click", myUlFn);

    function myUlFn(e) {
      if (e.target.tagName.toLowerCase() === 'li') { // 判断是否为所需要点击的元素
        console.log(`您点击了${e.target.innerText}`);
      }
    }

  </script>
</body>

</html>

注意:这是一般的事件委托方法,但是这种写法有问题,就是当_<li>_中还有子元素时,点击这个子元素就不会进行触发事件。这个问题是一个坑。

事件冒泡有时候确实很有用,但是有时候也讨人烦,当你不需要它的时候能不能取消掉呢?

三、禁止事件冒泡与捕获

注意:并不是所有事件都会冒泡,比如focus,blur,change,submit,reset,select等。

禁止冒泡和捕获可以用到方法stopPropagation()。
stopPropagation()起到阻止捕获和冒泡阶段中当前事件的进一步传播。
这是阻止事件的冒泡方法,进行冒泡,但是默认事件任然会执行,当你调用了这个方法后。
如果点击一个a标签,这个a标签会进行跳转。

使用起来也很简单,没有返回值也没有参数。

event.stopPropagation();

请看下面例子,这个例子实在上文事件冒泡例子基础上稍加修改得到的

    <div id="box1">
        <div id="box2">
            <div id="box3"></div>
        </div>
    </div>
    <script>
        const box1 = document.getElementById('box1')
        const box2 = document.getElementById('box2')
        const box3 = document.getElementById('box3')
        box1.onclick = sayBox1;
        box2.onclick = sayBox2;
        box3.onclick = sayBox3;
        function sayBox3() {
            console.log('你点了最里面的box');
        }
        function sayBox2(e) {
            console.log('你点了最中间的box');
            e.stopPropagation(); //禁止事件捕获和冒泡
        }
        function sayBox1() {
            console.log('你点了最外面的box');
        }
    </script>

当事件冒泡到box2时调用了在函数sayBox2,调用了e.stopPropagation(); 就停止冒泡了。

到此这篇关于JavaScript 事件捕获冒泡与捕获详情的文章就介绍到这了,更多相关JavaScript事件捕获冒泡与捕获内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

四、参考文献

MDN中文版 https://developer.mozilla.org/zh-CN/
知乎 https://zhuanlan.zhihu.com/p/26536815

(0)

相关推荐

  • js基础之事件捕获与冒泡原理

    想要了解什么是事件捕获与冒泡,需要先了解什么是事件. 什么是事件? 我们知道,在前端开发中,JavaScript负责定义网页的"行为".这里所说的"定义",其实指的是开发者可以通过JavaScript语言向浏览器描述一些规则,浏览器按照这些规则与用户进行交互.比如开发者希望当用户点击页面上某个按钮的时候,就弹出一个窗口,显示特定的内容.而当用户真正点击这个按钮的时候,浏览器将按照开发者定义的这个规则,去弹出指定的窗口,显示指定的内容. 在上面的例子中,浏览器是一切规

  • javascript事件冒泡,事件捕获和事件委托详解

    1.事件冒泡:在javascript事件传播过程中,当事件在一个元素上出发之后,事件会逐级传播给先辈元素,直到document为止,有的浏览器可能到window为止.并不是所有的事件都有冒泡现象,比如如下几个:blur事件 ,focus事件, load事件 2.事件委托:事件捕获恰好与事件冒泡相反,它从顶层祖先元素开始,直到事件触发元素. js事件捕获一般通过DOM2事件模型addEventListener来实现的: target.addEventListener(type, listener,

  • JavaScript 事件捕获冒泡与捕获详情

    目录 一.事件流 1.概念 2.DOM事件流 二.事件委托 1.事件委托的优点 2.事件委托的使用 三.禁止事件冒泡与捕获 四.参考文献 一.事件流 JavaScript中,事件流指的是DOM事件流. 1.概念 事件的传播过程即DOM事件流. 事件对象在 DOM 中的传播过程,被称为"事件流". 举个例子:开电脑这个事,首先你是不是得先找到你的电脑,然后找到你的开机键,最后用手按下开机键.完成开电脑这个事件.这整个流程叫做事件流. 2.DOM事件流 DOM事件,也是有一个流程的.从事件

  • 浅析js中事件冒泡与事件捕获

    目录 01-事件冒泡 1.1-事件冒泡介绍 1.2-事件冒泡利用(事件委托) 1.3-事件冒泡影响 与 阻止事件冒泡 02-事件捕获 1.1-事件捕获介绍 1.2-事件三个阶段 01-事件冒泡 1.1-事件冒泡介绍 本小节知识点:介绍什么是事件冒泡 事件冒泡:如果一个元素的事件被触发,那么他的所有父级元素的同名事件也会被依次触发 元素->父元素->body->html->document->window 事件冒泡一直存在,只不过以前我们没有给父级元素加同名事件 <!DO

  • js事件机制----捕获与冒泡机制实例分析

    本文实例讲述了js事件机制----捕获与冒泡机制.分享给大家供大家参考,具体如下: 先从事件绑定机制说起, 事件绑定机制通过绑定方法addEventListener()实现, 语法格式如下: element.addEventListener(event, function, useCapture) 参数值 参数 描述 event 必须.字符串,指定事件名. 注意: 不要使用 "on" 前缀. 例如,使用 "click" ,而不是使用 "onclick&qu

  • js点击事件的执行过程实例分析【冒泡与捕获】

    本文实例讲述了js点击事件的执行过程.分享给大家供大家参考,具体如下: js事件对象event包括很多事件类型,这里用onclick事件为例,探讨一下在js事件捕获机制和冒泡机制下的执行过程,以及如何阻止事件的捕获和冒泡. 首先看下当我们点击一个元素后,浏览器的执行过程. 1,当某个元素绑定的事件被触发时,这时浏览器就会从顶级document元素发出一个事件流 2,这个事件流顺着dom层级,一层一层向下找,直到遇到了触发事件的目标元素,这个查找的过程是捕获阶段 说明:捕获阶段,在查找每一层dom

  • javaScript 事件绑定、事件冒泡、事件捕获和事件执行顺序整理总结

    抽空学习了下javascript和jquery的事件设计,收获颇大,总结此贴,和大家分享. (一)事件绑定的几种方式 javascript给DOM绑定事件处理函数总的来说有2种方式:在html文档中绑定.在js代码中绑定.下面的方式1.方式2属于在html中绑定事件,方式3.方式4和方式5属于在js代码中绑定事件,其中方法5是最推荐的做法. 方式1: HTML的DOM元素支持onclick.onblur等以on开头属性,我们可以直接在这些属性值中编写javascript代码.当点击div的时候,

  • javascript事件冒泡详解和捕获、阻止方法

    一.事件的发生顺序 这个问题的起源非常简单,假设你在一个元素中又嵌套了另一个元素 复制代码 代码如下: ----------------------------------- | element1                        | |   -------------------------     | |   |element2               |     | |   -------------------------     | |                 

  • javascript事件冒泡和事件捕获详解

    事件冒泡和事件捕获分别由微软和网景公司提出,这两个概念都是为了解决页面中事件流(事件发生顺序)的问题. <div id="outer"> <p id="inner">Click me!</p> </div> 上面的代码当中一个div元素当中有一个p子元素,如果两个元素都有一个click的处理函数,那么我们怎么才能知道哪一个函数会首先被触发呢? 为了解决这个问题微软和网景提出了两种几乎完全相反的概念. 事件冒泡 微软提出

  • JavaScript事件冒泡与事件捕获实例分析

    本文实例讲述了JavaScript事件冒泡与事件捕获.分享给大家供大家参考,具体如下: 1.事件冒泡 在一个对象上触发某类事件,如onclick事件等,在其祖先节点上也会依次触发该事件. <body onclick="alert('body')"> <div onclick="alert('div')"> <a href="" onclick=" rel="external nofollow&qu

  • Javascript事件的捕获方式和冒泡方式详解

    目录 一.事件处理模型 1.事件冒泡 (1)给三个div元素绑定事件 (2)运行结果: 2.事件捕获 (1)给三个div元素绑定事件 (2)运行结果: 二.阻止事件冒泡 (1)w3c标准 event.stopPropagation();但ie9以下版本不支持 (2)ie独有:event.cancelBubble = true; (3)合并取消:return false 总结 一.事件处理模型 事件冒泡.捕获:事件冒泡和事件捕获分别由微软和网景公司提出,这两个概念都是为了解决页面中事件流(事件发生

  • javascript事件捕获机制【深入分析IE和DOM中的事件模型】

    本文实例分析了javascript事件捕获机制.分享给大家供大家参考,具体如下: 1.什么是事件冒泡? 在排序算法中,我们学过冒泡排序法,所谓冒泡就是让底层的东西浮出水面,对于事件冒泡也同样是如此, 下面我们来看一个例子来说明什么是事件冒泡. <div> <button>测试</button> </div> <script> $("div").bind("click",function(){alert(&q

  • 微信小程序事件绑定传参冒泡及捕获的示例详解

    目录 常见的事件有: currentTarget和target的区别 事件传递参数 touches和changedTouches的区别 事件的绑定两种方法 事件传参 事件的冒泡与事件的捕获 小结 常见的事件有: 类型 触发条件 最低版本 touchstart 手指触摸动作开始   touchmove 手指触摸后移动   touchcancel 手指触摸动作被打断,如来电提醒,弹窗   touchend 手指触摸动作结束   tap 手指触摸后马上离开   longpress 手指触摸后,超过35

随机推荐