【JS】事件流、事件冒泡、事件捕获、阻止冒泡、事件委托

2023-05-16

目录

事件:

什么是事件流

事件冒泡事件捕获

DOM事件处理

DOM0

DOM2

一个DOM元素同时绑定冒泡捕获,执行顺序:

阻止冒泡 

 阻止冒泡方法封装

Event事件对象的使用

事件委托

什么是事件委托

实现事件委托

事件委托的优点:


事件:

JavaScript和HTML之间的交互是通过事件实现的。事件,就是文档或浏览器窗口发生的一些特定的交互瞬间。可以使用监听器(或事件处理程序)来预定事件,以便事件发生时执行相应的代码。通俗的说,这种模型其实就是一个观察者模式。

什么是事件流

事件流描述的就是从页面中接收事件的顺序。而早期的IE和Netscape提出了完全相反的事件流概念,IE事件流是事件冒泡,而Netscape的事件流就是事件捕获。

事件冒泡事件捕获

IE提出的事件流是事件冒泡,即从下至上,从目标触发的元素逐级向上传播,直到window对象。

                          

而Netscape的事件流就是事件捕获,即从document逐级向下传播到目标元素。由于IE低版本浏览器不支持,所以很少使用事件捕获。

                                

后来ECMAScriptDOM2中对事件流进行了进一步规范,基本上就是上述二者的结合

DOM2级事件规定的事件流包括三个阶段(1)事件捕获阶段 (2)处于目标阶段 (3)事件冒泡阶段

DOM事件处理

DOM节点中有了事件,那我们就需要对事件进行处理,而DOM事件处理分为4个级别:DOM0级事件处理,DOM1级事件处理,DOM2级事件处理和DOM3级事件处理。

其中DOM1级事件处理标准中并没有定义相关的内容,所以没有所谓的DOM1事件处理;DOM3级事件在DOM2级事件的基础上添加了更多的事件类型。 

DOM0

DOM0级事件具有极好的跨浏览器优势,会以最快的速度绑定。第一种方式是内联模型(行内绑定),将函数名直接作为html标签中属性的属性值。

<div onclick="btnClick()">click</div>
<script>
function btnClick(){
    console.log("hello");
}
</script>

内联模型的缺点是不符合w3c中关于内容与行为分离的基本规范。第二种方式是脚本模型(动态绑定),通过在JS中选中某个节点,然后给节点添加onclick属性。

<div id="btn">点击</div>
<script>
var btn=document.getElementById("btn");
btn.onclick=function(){
    console.log("hello");
}
</script>

 点击输出 hello,没有问题;如果我们给元素添加两个事件

<div id="btn">点击</div>
<script>
var btn=document.getElementById("btn");
btn.onclick=function(){
    console.log("hello");
}
btn.onclick=function(){
    console.log("hello again");
}
</script>

 这时候只有输出 hello again,很明显,第一个事件函数被第二个事件函数给覆盖掉,所以脚本模型的缺点是同一个节点只能添加一次同类型事件。

当把div扩展到3个的时候:

<div id="btn3">
    btn3
    <div id="btn2">
        btn2
        <div id="btn1">
            btn1
        </div>
    </div>
</div>
<script>
    let btn1 = document.getElementById("btn1");
    let btn2 = document.getElementById("btn2");
    let btn3 = document.getElementById("btn3");
    btn1.onclick=function(){
        console.log(1)
    }
    btn2.onclick=function(){
        console.log(2)
    }
    btn3.onclick=function(){
        console.log(3)
    }
</script>

//点击bt1 输出  1   2    3

 在点击btn1的时候输出:如上

我们发现最先触发的是最底层 btn1 的事件,最后才是顶层btn3的事件,因此很明显是事件冒泡。DOM0 级只支持冒泡阶段。

                                    

DOM2

进一步规范之后,有了DOM2级事件处理程序,其中定义了两个方法:

  1. addEventListener() ---添加事件侦听器
  2. removeEventListener() ---删除事件侦听器

函数均有3个参数, 第一个参数是要处理的事件名 第二个参数是作为事件处理程序的函数 第三个参数是一个boolean值,默认false表示使用冒泡机制,true表示捕获机制。

addEventListener() 方法用于向指定元素添加事件句柄。element.addEventListener(event, function, useCapture)

如果一个函数是被事件调用的,那么这个函数定义的第一个参数就是事件对象

其中的 event,必须。字符串,指定事件名。 不要使用 "on" 前缀。 例如,使用 "click" ,而不是使用 "onclick"。

<div id="btn">点击</div>

<script>
var btn=document.getElementById("btn");
btn.addEventListener("click",hello,false);
btn.addEventListener("click",helloagain,false);
function hello(){
    console.log("hello");
}
function helloagain(){
    console.log("hello again");
}
</script>

这时候两个事件处理程序都能够成功触发,说明可以绑定多个事件处理程序,但是注意,如果定义了一摸一样时监听方法,是会发生覆盖的,即同样的事件和事件流机制下相同方法只会触发一次。

 当把div扩展到3个的时候:

<div id="btn3">
    btn3
    <div id="btn2">
        btn2
        <div id="btn1">
            btn1
        </div>
    </div>
</div>
<script>
    let btn1 = document.getElementById('btn1');
    let btn2 = document.getElementById('btn2');
    let btn3 = document.getElementById('btn3');
    btn1.addEventListener('click',function(){
        console.log(1)
    }, true)
    btn2.addEventListener('click',function(){
        console.log(2)
    }, true)
    btn3.addEventListener('click',function(){
        console.log(3)
    }, true)
</script>

//事件捕获
//点击btn1,输出 3   2   1

 这时候看到输出3  2  1,最外层的btn最先触发,因为addEventListener最后一个参数是true,捕获阶段进行处理。

一个DOM元素同时绑定冒泡捕获,执行顺序:

绑定在被点击元素的事件是按照代码顺序发生,其他元素通过冒泡或者捕获“感知”的事件,按照W3C的标准,先发生捕获事件,后发生冒泡事件。所有事件的顺序是:其他元素捕获阶段事件 -> 本元素代码顺序事件 -> 其他元素冒泡阶段事件 。

阻止冒泡、捕获

有时候我们需要点击事件不再继续向上冒泡,我们在btn2上加上stopPropagation函数,阻止程序冒泡。

btn1.addEventListener('click',function(){
    console.log('btn1冒泡')
}, false)
btn1.addEventListener('click',function(){
    console.log('btn1捕获')
}, true)

btn2.addEventListener('click',function(){
    console.log('btn2冒泡')
}, false)
btn2.addEventListener('click',function(ev){
    ev.stopPropagation();
    console.log('btn2捕获')
}, true)

btn3.addEventListener('click',function(){
    console.log('btn3冒泡')
}, false)
btn3.addEventListener('click',function(e){
    console.log('btn3捕获')
}, true)

点击btn1,然而在btn2捕获阶段执行后不再继续往下执行。

 阻止冒泡方法封装

<script>
var wrap = document.getElementsByTagName('div')[0]
var box = document.getElementsByTagName('div')[1]
var btn = document.getElementsByTagName('div')[2]
function addEvent(el, type, handle, bool) {
// addEventlistener attachEvent
if (el.addEventlistener) { // 非IE 9以上
el.addEventlistener(type, handle, bool)
} else if (el.attachEvent) {
el.attachEvent('on' + type, function () {
handle.call(el) // 改变this 指向;由默认的window变为当前的对象
}, bool)
} else { // 直接给元素对象绑定事件
el['on' + type] = handle
}
}
addEvent(wrap, 'click', function (e) {
console.log('wrap')
wrap.style.background = 'black';
stop(e)
}, false)
addEvent(box, 'click', function (e) {
console.log('box')
box.style.background = 'black'
stop(e)
}, false)
addEvent(btn, 'click', function (e) {
console.log('btn')
btn.style.background = 'black'
stop(e)
}, false)
// 阻止冒泡方法封装
function stop(e){
e = e || window.event
if (e.stopPropagation) {
// 这里的e = 形参e
e.stopPropagation()
} else { // IE9以下
// 这里的 e = window.event
// 阻止默认时间 true阻止;false不阻止
e.cancelBubble = true;
}
}
</script>

Event事件对象的使用

  • 直接通过event来获取
  • 通过函数传参数的形式
  • 还可以通过函数传参数的形式来使用,一般而言我们使用【形参e或event】来代替。

事件委托

什么是事件委托

事件委托/事件代理:事件委托就是利用【事件冒泡】,自己本身做不了这个事,让让上一级来做这个事,只指定一个事件处理程序,就可以管理某一类型的所有事件。

如果有多个DOM节点需要监听事件的情况下,给每个DOM绑定监听函数,会极大的影响页面的性能,因为我们通过事件委托来进行优化,事件委托利用的就是冒泡的原理。

<ul>
    <li>1</li>
    <li>2</li>
    <li>3</li>
    <li>4</li>
    <li>5</li>
</ul>
<script>
    var li_list = document.getElementsByTagName('li')
    for(let index = 0;index<li_list.length;index++){
        li_list[index].addEventListener('click', function(ev){
            console.log(ev.currentTarget.innerHTML)
        })
    }
</script>

正常情况我们给每一个li都会绑定一个事件,但是如果这时候li是动态渲染的,数据又特别大的时候,每次渲染后(有新增的情况)我们还需要重新来绑定,又繁琐又耗性能;这时候我们可以将绑定事件委托到li的父级元素,即ul。

实现事件委托

var ul_dom = document.getElementsByTagName('ul')
ul_dom[0].addEventListener('click', function(ev){  
    console.log(ev.target.innerHTML)
})

 上面代码中我们使用了两种获取目标元素的方式,targetcurrentTarget,那么他们有什么区别呢:

  • target 返回触发事件的元素,不一定是绑定事件的元素
  • currentTarget 返回的是绑定事件的元素

事件委托的优点:

  1. 提高性能:每一个函数都会占用内存空间,只需添加一个事件处理程序代理所有事件,所占用的内存空间更少。
  2. 动态监听:使用事件委托可以自动绑定动态添加的元素,即新增的节点不需要主动添加也可以一样具有和其他元素一样的事件。
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

【JS】事件流、事件冒泡、事件捕获、阻止冒泡、事件委托 的相关文章

  • 使用docker发布.net应用

    步骤 xff1a 创建 NET应用样例 创建包含生成 NET镜像所需引导的Dockerfile 构建一个镜像并基于此创建一个容器 设置容器数据卷和网络设置 使用Docker Compose编排容器 使用容器构建开发坏境 创建镜像 先决条件
  • python计算机视觉--全景图像拼接

    目录 一 RANSAC算法 1 1 RANSAC算法简介 1 2 算法基本思想和流程 1 3 RANSAC求解单应性矩阵 二 图像映射与全景拼接 2 1 简介 2 2 计算第二张图像与第一张图像之间的变换关系 2 3 将第二张图像叠加到第一
  • px4自带教程offboard下的gazebo多无人机编队仿真

    px4自带教程offboard下的gazebo多无人机编队仿真 主要教程参考这篇文章 xff0c offboard代码也源自下面链接 xff0c 增加了其他文件的配置细节 xff0c 链接如下 xff1a https blog csdn n
  • rotors_simulator与sitl_gazebo冲突导致报错“gzserver....”

    rotors simulator与sitl gazebo冲突导致报错 gzserver 创建时间2021 04 14 报错图片详见2021 04 14屏幕截图 总是出现gzserver symbol lookup error home zy
  • 安装ROS、gazebo、PX4基础细节及offboard控制

    新手参考教程安装ROS gazebo PX4基础细节及offboard控制 1 安装ROS 参考教程 2 安装PX4 参考教程 注 xff1a 1 在编译px4 Firmware前会经过安装步骤 xff0c 安装需要去github上git
  • 无人机模型记录

    今天看了这篇知乎 xff0c 收获非常大 xff0c 实现了一个非常基础的无人机动力学以及运动学模型 xff0c 包括公式推导等 xff0c 也解决了困扰我很久的问题 xff0c 在此基础上就可以加入控制算法 xff0c 设置轨迹等 htt
  • VMware安装Ubuntu20.04.5常见问题及解决方案

    文章目录 使用Xftp连接ubuntu系统ubuntu上安装指定版本nodejsubuntu设置连网ubuntu安装Java8ubuntu安装 deb格式软件ubuntu卸载 deb格式软件ubuntu中electron框架安装的缓存在如下
  • 无人机控制输入、PID控制

    无人机控制输入 PID控制 最近思路比较乱 xff0c 看到很多东西 xff0c 因为有各种控制 xff0c 需要在这里记录总结 控制输入 结合以下两个链接理解虚拟控制输入U1 U2 U3 U4 1 https blog csdn net
  • FreeRTOS学习(3)——任务创建和删除(静态)

    本代码是基于正点原子的STM32Mini板子 xff0c 结合其FreeRTOS课程进行学习 实验一 xff1a 设计4个任务 xff1a start task task1 task2 task3 start task任务 xff1a 用来
  • 华三交换机配置定时重启任务

    组网及说明 1 配置需求或说明 1 1 适用产品系列 本案例适用于如S7006 S7503E S7506E S7606 S10510 S10508等S7000 S7500E S10500系列 xff0c 且软件版本是V7的交换机 1 2 配
  • RTK差分通讯链路---Ntrip DTU(支持千寻位置,CORS站、自建站)

    在之前的博客中提到RTK差分通讯链路 电台 RTK技术的关键在于其获取了载波相位的观测量 xff0c 通过架设基准站和移动站 xff0c 利用电台的通讯方式 xff0c 使得移动站通过差分方式消除观测数据误差实现高精度 还有一种通讯方式 x
  • 北斗/GPS如何处理定位漂移?

    漂移是北斗 GPS导航时需要处理的问题之一 xff0c 漂移主要有两个方面 xff0c 第一 xff0c 速度过快 xff0c 以至于北斗 GPS的响应时间短于当前运行速度 xff0c 出现漂移 xff1b 第二 xff0c 在高大建筑密集

随机推荐

  • Jetson nx批量复制

    Jetson NX 批量克隆教程 文章目录 Jetson NX 批量克隆教程一 批量克隆是什么 xff1f 二 克隆步骤1 准备材料2 备份镜像3 克隆新SD卡 解压失败问题参考 一 批量克隆是什么 xff1f 辛辛苦苦在Jetson Xa
  • FreeRTOS一些常识笔记之快速上手

    一 为啥要用实时多任务操作系统 real time Operate System 简称有 xff1a RTOS xff0c 有如下的好处 用户无需关心时间信息 内核负责计时 xff0c 并由相关的API完成 xff0c 从而使得用户的应用程
  • Prometheus+node_exporter+grafana监控部署(上)

    目录 一 部署Prometheus 二 部署node exporter 三 把node exporter加载进Prometheus 四 部署grafana 一 部署Prometheus 1 从官网下载好Prometheus的安装包 2 解压
  • Zookeeper入门篇

    Zookeeper特性 xff1a Zookeeper xff1a 一个领导者 xff08 Leader xff09 xff0c 多个跟随者 xff08 Follower xff09 组成的集群 集群中只要有半数以上 xff08 不包括半数
  • 源码编译ROS的导航包navigation、编译navigation、也有安装navigation二进制包方式

    1 创建工作空间 span class token function mkdir span nav ws src p span class token function cd span nav ws src catkin init work
  • 深度无人机的视觉检测与跟踪神经网络:性能基准

    Unmanned Aerial Vehicle Visual Detection and Tracking using DeepNeural Networks A Performance Benchmark 深度无人机的视觉检测与跟踪神经网
  • 基于yolov5+fastreid+deepsort的TensorRT目标跟踪(C++版)复现过程

    基于yolov5 43 fastreid 43 deepsort的TensorRT目标跟踪 大部分的多目标跟踪项目都是用Python写的 xff0c 但是C 43 43 版本能够用TensorRT进行加速 xff0c 适合在边缘端部署 xf
  • JavaScript之定时器

    定时器 一 setTimeout 定时器二 停止 setTimeout 定时器三 setInterval 定时器四 清除setInterval 定时器五 电子时钟案例 在很多页面中 xff0c 我们都可以看到一些倒计时或者和时间相关的效果
  • JavaScript - 防抖与节流 基础代码

    防抖 无论触发了多少次函数 只执行最后一次函数 多次触发合并为一次 span class token tag span class token tag span class token punctuation lt span body sp
  • 一、QGC源码下载以及配置

    QGC V3 4版本 源码存放地址 https github com mavlink qgroundcontrol 下载方式 xff1a 1 git xff1a git clone https github com mavlink qgro
  • 无法被检测到的Linux恶意软件

    网络安全研究人员今天发现了一种完全无法被检测到的Linux恶意软件 xff0c 该恶意软件利用未公开的技术来监视并瞄准以流行的云平台 xff08 包括AWS xff0c Azure和阿里云 xff09 托管的可公开访问的Docker服务器
  • C++中的重难点看这一篇就够了

    sizeof 是一个运算符 xff0c 不是一个函数 看程序效率的快慢 xff0c 可以直接看其汇编语言程序的多少 扩展名 xff1a c语言 xff1a c c 43 43 xff1a cpp Java xff1a 先有类 xff0c 再
  • git 记录一次合并冲突的解决办法

    合并冲突 将远程分支拉到本地 xff0c 执行 git merge 39 分支名 39 时 xff0c 报错 xff1a CONFLICT content Merge conflict in 文件路径名 冲突出现在xx文件里面 Automa
  • 2020-11-10

    将Tomcat整合到Eclipse中 将Tomcat服务器整合到Eclipse工具中 xff0c 可以通过Eclipse启动 关闭tomcat服务器 xff0c 更重要的是 xff0c 可以非常方便的将在Eclipse中创建的Web项目发布
  • Ubuntu18.04搭建 SLAM环境(完美避坑,版本对应不报错)

    Ubuntu18 04搭建 SLAM环境 写到前言一 CMake g 43 43 git的安装二 Eigen的配置三 Sophus的配置四 OpenCV PCL Pangolin的配置安装1 OpenCV的配置2 PCL3 Pangolin
  • linux下运行.sh脚本提示syntax error: unexpected end of file的解决方法

    转载自 xff1a https www jb51 net article 179414 htm CentOS7运行 sh脚本提示syntax error unexpected end of file的解决方法 更新时间 xff1a 2020
  • JS高级编程 - - day03

    一 获取节点示例的方法 直接获取节点实例 xff1a 1 通过内置对象 document 获取 xff0c document对象是HTMLDocument的实例 2 获取根元素的实例 xff1a document documentEleme
  • Python学习笔记——argparse中的action=store_true用法

    前言 Python的命令行参数解析模块学习 示例 参数解析模块支持action参数 xff0c 这个参数可以设置为 store true store false 39 store const 等 例如下面这行代码 xff0c 表示如果命令行
  • 阿里云服务器更换Ubuntu操作系统并配置图形界面

    文章目录 阿里云服务器更换Ubuntu操作系统并配置图形界面环境目标更换操作系统登录阿里云服务器管理控制台进入实例管理页面停止实例更换操作系统 配置图形界面远程连接到服务器配置图形界面配置Ubuntu 阿里云服务器更换Ubuntu操作系统并
  • 【JS】事件流、事件冒泡、事件捕获、阻止冒泡、事件委托

    目录 事件 xff1a 什么是事件流 事件冒泡事件捕获 DOM事件处理 DOM0 DOM2 一个DOM元素同时绑定冒泡捕获 xff0c 执行顺序 xff1a 阻止冒泡 阻止冒泡方法封装 Event事件对象的使用 事件委托 什么是事件委托 实