深度剖析JavaScript中冒泡和捕获机制、事件代理

news2024/12/24 10:50:07

   JS事件传播的两种机制包括冒泡和捕获,下面将具体剖析它们之间本质的区别。


   事件冒泡: 先触发子元素的事件,再触发父元素的事件。


   创建一个 ul label 和 li label, 分别绑定一个父id 和 子 id, 再通过创建 script,去绑定各自的点击事件。



在这里插入图片描述



<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
    <ul id="father">
        我是一个无序列表
        <li id="son">1个列表项</li>
    </ul>

    <script>
        document.getElementById('father').onclick = function(){
            console.log('我点击了父元素');
        }

        document.getElementById('son').onclick = function(){
            console.log('我点击了子元素');
        }

    </script>
</body>

</html>


   当我点击 "第1个列表项"后,在Console先输出的是 “我点击了子元素”, 然后是 “我点击了父元素”, 可见冒泡的执行顺序是由里向外,也就是从 li - ul - body - document - window 这样的执行顺序,就好比人扔了一块石头去河里,先是冒一个小泡,再逐个现成大的水泡这种扩散现象。因此,JS默认的点击事件就是冒泡。



在这里插入图片描述



   事件捕获: 先触发父元素的事件,再触发子元素的事件。如果要将冒泡改为捕获,需要添加监听事件。监听事件的第3个参数必须为 “true”, 默认为 false 。



在这里插入图片描述



<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
    <ul id="father">
        我是一个无序列表
        <li id="son">1个列表项</li>
    </ul>

    <script>
        // document.getElementById('father').onclick = function(){
        //     console.log('我点击了父元素');
        // }

        document.getElementById('father').addEventListener('click',function(){
            console.log('我点击了父元素');
        },true);

        document.getElementById('son').onclick = function(){
            console.log('我点击了子元素');
        }

    </script>
</body>

</html>


    再点击 "第1个列表项"后,控制台先输出的是 “我点击了父元素”, 然后是 “我点击了子元素”, 可见捕获的执行顺序是由外向里,也就是从 window - documment - body - ul - li 这样的执行顺序。



在这里插入图片描述



    事件代理是指利用事件冒泡,只指定一个事件处理程序,就可以管理某一类型的所有事件。


    先复制多几个 li label



在这里插入图片描述



<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
    <ul id="father">
        我是一个无序列表
        <li id="son">1个列表项</li>
        <li id="son">2个列表项</li>
        <li id="son">3个列表项</li>
        <li id="son">4个列表项</li>
        <li id="son">5个列表项</li>
    </ul>

    <script>
        // document.getElementById('father').onclick = function(){
        //     console.log('我点击了父元素');
        // }

        document.getElementById('father').addEventListener('click',function(){
            console.log('tesing for 事件代理');
        },true);

        // document.getElementById('son').onclick = function(){
        //     console.log('我点击了子元素');
        // }

    </script>
</body>

</html>


   例如然后点击 “第5个列表项”,由于冒泡作用,当点击到 li label,冒泡到 ul label 上,执行了 ul label上的点击事件,最后在 Console 输出了 “tesing for 事件代理”。



在这里插入图片描述



在这里插入图片描述



   通常父级那么多子元素,怎样去区分事件本应该是哪个子元素呢?在 function() 函数里面添加一个 event param, 稍后在Console打印这个 event 的 object



在这里插入图片描述



   例如当点击 “第4个列表项” 后,就会输出了 event 这个 object



在这里插入图片描述



   点击 “target” 继续展开后续的内容

在这里插入图片描述



   展开后,可见还有省略的内容,点击 “…” 这个省略的位置后,可以继续展示余下隐藏的内容。



在这里插入图片描述



   展开后,可见 textContent : “第4个列表项”



在这里插入图片描述



   添加判断条件为 点击 "第4个列表项"时,才会打印 “tesing for 事件代理”, 点击其它元素没有任何内容输出。



在这里插入图片描述



<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
    <ul id="father">
        我是一个无序列表
        <li id="son">1个列表项</li>
        <li id="son">2个列表项</li>
        <li id="son">3个列表项</li>
        <li id="son">4个列表项</li>
        <li id="son">5个列表项</li>
    </ul>

    <script>
        // document.getElementById('father').onclick = function(){
        //     console.log('我点击了父元素');
        // }

        document.getElementById('father').addEventListener('click',function(event){
            if (event.target.textContent === "第4个列表项"){
            console.log('tesing for 事件代理');
            };
            // console.log(event);
        },true);

        // document.getElementById('son').onclick = function(){
        //     console.log('我点击了子元素');
        // }

    </script>
</body>

</html>


   怎么取消冒泡或者捕获 ? 通过 event.stopPropagation() 方法可以实现。



在这里插入图片描述



<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
    <ul id="father">
        我是一个无序列表
        <li id="son">1个列表项</li>
        <!-- <li id="son">2个列表项</li>
        <li id="son">3个列表项</li>
        <li id="son">4个列表项</li>
        <li id="son">5个列表项</li> -->
    </ul>

    <script>
        // document.getElementById('father').onclick = function(){
        //     console.log('我点击了父元素');
        // }

        // document.getElementById('father').addEventListener('click',function(event){
        // //     if (event.target.textContent === "第4个列表项"){
        // //     console.log('tesing for 事件代理');
        // //     };
        // //     // console.log(event);
        // // },true);

        // document.getElementById('son').onclick = function(){
        //     console.log('我点击了子元素');
        // }

        document.getElementById('father').addEventListener('click',function(event){
            console.log('testing for click father element');
        });

        document.getElementById('son').addEventListener('click',function(event){
            console.log('testing for click son element');
            event.stopPropagation();
        });


    </script>
</body>

</html>


   再次点击 “第1个列表项” 后,只执行子元素输出 “testing for click son element”,不再执行父元素, 也就是不再输出 “testing for click father element”, 取消了冒泡。



在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1317799.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Threejs利用着色器编写动态飞线特效

一、导语 动态飞线特效是可视化数据地图中常见的需求之一&#xff0c;鼠标点击的区块作为终点&#xff0c;从其他区块飞线至点击区块&#xff0c;附带颜色变换或者结合粒子动画 二、分析 利用创建3点来构成贝塞尔曲线&#xff0c;形成线段利用着色器材质来按照线段以及时间…

Linux---压缩和解压缩命令

1. 压缩格式的介绍 Linux默认支持的压缩格式: .gz.bz2.zip 说明: .gz和.bz2的压缩包需要使用tar命令来压缩和解压缩.zip的压缩包需要使用zip命令来压缩&#xff0c;使用unzip命令来解压缩 压缩目的: 节省磁盘空间 2. tar命令及选项的使用 命令说明tar压缩和解压缩命令 …

SE考研真题总结(三)

继续更新&#xff0c;今天准备连出两期该系列~ SE考研真题总结&#xff08;二&#xff09;https://blog.csdn.net/jsl123x/article/details/134857052?spm1001.2014.3001.5501 目录 一.简答题 二.代码大题 一.简答题 1.工程和科学的区别 科学是关于事物的基本原理和事实的…

代码随想录算法训练营 | day53 动态规划 1143.最长公共子序列,1035.不相交的线,53.最大子序和

刷题 1143.最长公共子序列 题目链接 | 文章讲解 | 视频讲解 题目&#xff1a;给定两个字符串 text1 和 text2&#xff0c;返回这两个字符串的最长公共子序列的长度。 一个字符串的 子序列 是指这样一个新的字符串&#xff1a;它是由原字符串在不改变字符的相对顺序的情况下…

Android动画(四)——属性动画ValueAnimator的妙用

目录 介绍 效果图 代码实现 xml文件 介绍 ValueAnimator是ObjectAnimator的父类&#xff0c;它继承自Animator。ValueAnimaotor同样提供了ofInt、ofFloat、ofObject等静态方法&#xff0c;传入的参数是动画过程的开始值、中间值、结束值来构造动画对象。可以将ValueAnimator看…

C#深拷贝效率对比

对于浅拷贝和深拷贝&#xff0c;前面的文章已经说明了。 C#浅拷贝和深拷贝数据-CSDN博客 本篇说一下&#xff0c;深拷贝的效率问题&#xff0c;效率一直是程序追求的&#xff0c;效率越高肯定越好&#xff0c;有时候功能是实现了&#xff0c;但是运行以及处理数据的效率非常低…

【算法】bfs与dfs算法解决FloodFill(洪流)问题(C++)

文章目录 1. 什么是FloodFill问题2. 用什么方法解决FloodFill问题3. 具体例题773.图像渲染200.岛屿数量695.岛屿的最大面积130.被围绕的区域 1. 什么是FloodFill问题 一般floodfill问题可以描述为&#xff1a;给定一个二维矩阵&#xff0c;其中每个元素代表一个像素点&#xf…

Python-flask 入门代码

python与pycharm安装 过程略&#xff0c;网上很多&#xff0c;记得为pycharm配置默认解释器 虚拟环境 pipenv # 全局安装虚拟环境 # 可加-U参数&#xff0c;明确全局安装&#xff0c;不加好像也可以? pip3 install pipenv #检查安装情况 pipenv --version # ---控制台输出…

跨域的解决方式(java后端)

文章目录 一、跨域介绍1、什么是跨域2、为什么会产生跨域3、禁止跨域的原因 二、简单请求和非简单请求1、简单请求1.1、什么时简单请求1.2、简单请求基础流程 2、非简单请求2.1、预检请求2.2、预检请求的回应2.3、浏览器的正常请求和回应 3、自定义跨域过滤器 三、解决方式1、C…

Java基础语法之抽象类和接口

抽象类 什么是抽象类 并不是所有的类都是用来描述对象的&#xff0c;这样的类就是抽象类 例如&#xff0c;矩形&#xff0c;三角形都是图形&#xff0c;但图形类无法去描述具体图形&#xff0c;所以它的draw方法无法具体实现&#xff0c;这个方法就可以没设计成抽象方法&…

003 Windows用户与组管理

Windows用户管理 一、用户账户 1、什么是用户账户 不同用户身份拥有不同的权限每个用户包含了一个名称和一个密码每个用户账户具有唯一的安全标识符查看系统中的用户 net user 安全标识符&#xff08;SID&#xff09; whoami /user 使用注册表查看 打开注册表命令regedi…

Sentinel使用详解

组件简介 Sentinel是阿里开源的一套用于服务容错的综合性解决方案。它以流量为切入点&#xff0c;从流量控制、熔断降级、系统负载保护等多个维度来保护服务的稳定性。Sentinel承接了阿里巴巴近10年的双十一大促流量的核心场景&#xff0c;例如秒杀、消息削峰填谷、集群流量控…

Java集合-12

Map的接口特点 key重复时会进行替换 package com.edu.map;import java.util.HashMap; import java.util.Map; import java.util.Set;SuppressWarnings({"all"}) public class Demo01 {public static void main(String[] args) {Map map new HashMap<>();map.…

并查集<基于ranks 的优化,基于Path Spliting的优化>

需求分析 假设有n个村庄&#xff0c;有些村庄之间有连接的路&#xff0c;有些村庄之间并没有连接的路 请你设计一个数据结构&#xff0c;能够快速执行2个操作 ◼ 查询2个村庄之间是否有连接的路◼ 连接2个村庄 首先思考在现有的数据结构能否实现上面的功能&#xff0c;数组、…

JVM学习之运行时数据区

运行时数据区 概述 内存 内存是非常重要的系统资源&#xff0c;是硬盘和CPU的中间桥梁&#xff0c;承载着操作系统和应用程序的实时运行。JVM内存布局规定了Java在运行过程中内存申请&#xff0c;分配&#xff0c;管理的策略&#xff0c;保证了JVM高效稳定运行。不同的JVM对于…

HTTP 302错误:临时重定向

在Web开发中&#xff0c;HTTP状态码是用于表示Web服务器响应的各种状态。其中&#xff0c;HTTP 302错误表示临时重定向&#xff0c;这意味着请求的资源已被临时移动到其他位置&#xff0c;并且服务器已经提供了新的URL&#xff0c;以便客户端可以重新发送请求。 了解HTTP 302错…

[计网01] 物理层 详细解析笔记,特性

计算机网络的物理层是网络协议栈中的第一层&#xff0c;负责传输原始的比特流&#xff08;bitstream&#xff09;通过物理媒介进行通信。物理层主要关注传输介质、信号的编码和调制、数据传输速率以及数据传输的物理连接等方面。 相关特性 机械特性&#xff08;Mechanical Ch…

网络安全—学习溯源和日志分析

日志分析的步骤&#xff1a; 判断是否为攻击行为 不是&#xff1a;不用处理 是&#xff1a;判断攻击是否成功或者失败 攻击失败&#xff1a;判断IP地址是否为恶意地址&#xff0c;可以让防火墙过滤IP地址 攻击成功&#xff1a;做应急处置和溯源分析 应急处置&#xff1a;网络下…

[楚慧杯 2023] web

文章目录 eaaevalupload_shell eaaeval 打开题目&#xff0c;源码给了用户密码 登陆后啥也没有&#xff0c;扫一下发现源码泄露www.zip <?php class Flag{public $a;public $b;public function __construct(){$this->a admin;$this->b admin;}public function _…

Python计算圆的面积,几何学技法大解析!

更多Python学习内容&#xff1a;ipengtao.com 大家好&#xff0c;我是彭涛&#xff0c;今天为大家分享 Python计算圆的面积&#xff0c;几何学技法大解析&#xff0c;全文3800字&#xff0c;阅读大约15分钟。 在本文中&#xff0c;将深入探讨如何使用 Python 计算圆的面积&…