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(事件类型,事件处理函数,获取捕获或者冒泡阶段)
  • 匿名函数无法被解绑
相关推荐
Qrun41 分钟前
Windows11安装nvm管理node多版本
前端·vscode·react.js·ajax·npm·html5
中国lanwp42 分钟前
全局 npm config 与多环境配置
前端·npm·node.js
JELEE.2 小时前
Django登录注册完整代码(图片、邮箱验证、加密)
前端·javascript·后端·python·django·bootstrap·jquery
TeleostNaCl4 小时前
解决 Chrome 无法访问网页但无痕模式下可以访问该网页 的问题
前端·网络·chrome·windows·经验分享
前端大卫5 小时前
为什么 React 中的 key 不能用索引?
前端
你的人类朋友5 小时前
【Node】手动归还主线程控制权:解决 Node.js 阻塞的一个思路
前端·后端·node.js
小李小李不讲道理7 小时前
「Ant Design 组件库探索」五:Tabs组件
前端·react.js·ant design
毕设十刻7 小时前
基于Vue的学分预警系统98k51(程序 + 源码 + 数据库 + 调试部署 + 开发环境配置),配套论文文档字数达万字以上,文末可获取,系统界面展示置于文末
前端·数据库·vue.js
mapbar_front8 小时前
在职场生存中如何做个不好惹的人
前端
牧杉-惊蛰8 小时前
纯flex布局来写瀑布流
前端·javascript·css