Web APIs——事件流

一、事件流

1.1 事件流与两个阶段说明

事件流指的是事件完整执行过程中的流动路径

说明:假设页面里有个div,当触发事件时,会经历两个阶段,分别是捕获阶段、冒泡阶段

简单来说:捕获阶段是 从父到子 冒泡阶段是从子到父

实际工作都是使用事件冒泡为主

1.2 事件捕获

从DOM的根元素开始去执行对应的事件(从外到里)

事件捕获需要写对应代码才能看到效果

DOM.addEventListener(事件类型,事件处理函数,是否使用捕获机制)

javascript 复制代码
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <style>
        .father {
            width : 500px;
            height: 500px;
            background-color:blueviolet;
        }
        .son {
            width: 200px;
            height: 200px;
            background-color: palegreen;
        }
    </style>
</head>
<body>
    <div class="father">
        <div class="son"></div>
    </div>
    <script>
        const fa = document.querySelector('.father')
        const son = document.querySelector('.son')
        document.addEventListener('click',function(){
            alert('我是爷爷')
        },true)
        fa.addEventListener('click',function(){
            alert('我是爸爸')
        },true)
        son.addEventListener('click',function(){
            alert('我是儿子')
        },true)
        // 捕获阶段简单来说就是从大的往小的查找,如果你都注册了同一事件,那它从大的往下依次执行,知道找到你要查找的那个
    </script>
</body>
</html>

事件捕获:当鼠标点击或者触发dom事件时(被触发dom事件的这个元素被叫作事件源),浏览器会从根节点=>事件源(由外到内)进行事件传播。

事件捕获与事件冒泡是比较类似的,最大的不同在于事件传播的方向。

说明:

  • addEventListener第三个参数为true表示捕获阶段触发(很少使用)
  • 若传入false表示冒泡阶段触发,默认值为false
  • 事件流只会在父子元素具有相同事件类型时才会产生影响
  • 若是用L0事件监听,则只有冒泡阶段,没有捕获

1.3 事件冒泡

当一个元素的事件被触发时,同样的事件将会在该元素的所有祖先元素中依次被触发。这一过程被称为事件冒泡。

简单理解:当一个元素触发事件后,会依次向上调用所有父级元素的 同名事件

事件冒泡是默认存在的

L2事件监听第三个参数是false,或者默认都是冒泡

1.4 阻止冒泡

问题:因为默认就有冒泡模式的存在,所有容易导致事件影响到父级元素

需求:若想把事件就限制在当前元素内,就需要阻止事件冒泡

前提:阻止事件冒泡需要拿到事件对象

语法:

事件对象.stopPropagation()

注意:此方法可以阻断事件流动传播,不光在冒泡阶段有效,捕获阶段也有效

javascript 复制代码
   <script>
        const fa = document.querySelector('.father')
        const son = document.querySelector('.son')
        document.addEventListener('click',function(){
            alert('我是爷爷')
        })
        fa.addEventListener('click',function(){
            alert('我是爸爸')
        })
        son.addEventListener('click',function(e){
            alert('我是儿子')
            // 组织流动传播  
            e.stopPropagation()
        })

    </script>

1.5 解绑事件

on事件方式,直接使用null覆盖就可以实现事件的解绑

语法:

// 绑定事件

btn.onclick = function () {

alert('点击了')

}

// 解绑事件

btn.onclick = null

javascript 复制代码
<body>
    <button>点击</button>
    <script>
        const btn = document.querySelector('button')
        // 绑定事件
        btn.onclick = function () {
            alert('点击了') // 会有提示框弹出
            // L0 事件移除解绑
            btn.onclick = null  // 不会弹出提示框,因为已经解绑了
        }
    </script>
</body>

addEventListener方式,必须使用:

removeEventListener(事件类型,事件处理函数,[获取捕获或者冒泡阶段])

javascript 复制代码
<body>
    <button>点击</button>
    <script>
        const btn = document.querySelector('button')
        function fn() {
            alert('点击了')
        }
        // 绑定事件
        btn.addEventListener('click',fn)
        // 解绑事件
        btn.removeEventListener('click',fn)
    </script>
</body>

注意:匿名函数无法解绑

二、鼠标结果事件的区别

鼠标经过事件:

  • mouseover和mouseout会有冒泡效果
  • mouseenter和mouseleave没有冒泡效果(推荐)

使用mouseover和mouseout

javascript 复制代码
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <style>
        .dad {
            width: 400px;
            height: 400px;
            background-color: brown;
        }
        .baby {
            width: 200px;
            height: 200px;
            background-color: gold;
        }
    </style>
</head>
<body>
    <div class="dad">
        <div class="baby"></div>
    </div>
    <script>
        // 使用mouseover和mouseout,
        const dad = document.querySelector('.dad')
        const baby = document.querySelector('.baby')
        dad.addEventListener('mouseover',function () {
            console.log('鼠标经过');
        })
        
        dad.addEventListener('mouseout',function () {
            console.log('鼠标移开');
        })
    </script>
</body>
</html>

运行结果:

使用mouseenter和mouseleave

javascript 复制代码
    <script>
        // 使用mouseenter和mouseleave,
        const dad = document.querySelector('.dad')
        const baby = document.querySelector('.baby')
        dad.addEventListener('mouseenter',function () {
            console.log('鼠标经过');
        })
        
        dad.addEventListener('mouseleave',function () {
            console.log('鼠标移开');
        })
    </script>

运行结果:

三、两种注册事件的区别

3.1 传统on注册(L0)

  • 同一个对象,后面注册的事件会覆盖前面注册(同一个事件)
  • 直接使用null覆盖偶就可以实现事件的解绑
  • 都是冒泡阶段执行的

3.2 事件监听注册(L2)

  • 语法:addEventListener(事件类型,事件处理函数,是否使用捕获)
  • 后面注册的事件不会覆盖前面注册的事件(同一个事件)
  • 可以通过第三个参数去确定是在冒泡或者捕获阶段执行
  • 必须使用removeEventListener(事件类型,事件处理函数,获取捕获或者冒泡阶段)
  • 匿名函数无法被解绑
相关推荐
却尘6 分钟前
Next.js 请求最佳实践 - vercel 2026一月发布指南
前端·react.js·next.js
ccnocare7 分钟前
浅浅看一下设计模式
前端
Lee川11 分钟前
🎬 从标签到屏幕:揭秘现代网页构建与适配之道
前端·面试
Ticnix38 分钟前
ECharts初始化、销毁、resize 适配组件封装(含完整封装代码)
前端·echarts
纯爱掌门人41 分钟前
终焉轮回里,藏着 AI 与人类的答案
前端·人工智能·aigc
twl1 小时前
OpenClaw 深度技术解析
前端
崔庆才丨静觅1 小时前
比官方便宜一半以上!Grok API 申请及使用
前端
星光不问赶路人1 小时前
vue3使用jsx语法详解
前端·vue.js
天蓝色的鱼鱼1 小时前
shadcn/ui,给你一个真正可控的UI组件库
前端
布列瑟农的星空1 小时前
前端都能看懂的Rust入门教程(三)——控制流语句
前端·后端·rust