面试题:事件触发过程是什么样的?

浅聊一下

试想一下,我们有三个div,每个div上有一个点击事件,点击最大的div会输出app,点击中间的div会输出wrap,点击最小的div会输出box。那么当我们点击分别点击每一个图层时会输出什么呢?本篇文章将带大家来深入分析一下事件的触发过程...

事件的触发过程

捕获过程

事件触发的第一个过程是捕获过程,在window上往事件触发处传播,遇到注册的捕获事件会触发(从外往内传播)

  • 点击app

点击app,会从window开始往里找,第一步就找到了app,于是输出app

  • 点击wrap

点击wrap,会从window开始往里找,先找到app,再找到wrap,那么我们的输出结果应该是app->wrap 但是结果真的是这样吗?不是, 输出结果为wrap->app

为什么会发生这种情况呢??? 因为在监听器中除了点击事件,触发方法,还有一个可选的参数,参数为布尔值,默认为false

如果第三个参数为true,那么在捕获事件过程捕获到的事件就会触发,如果为false,也就是默认,那就是在冒泡过程触发,所以在这里我们在冒泡过程触发事件,先输出wrap再输出app

js 复制代码
     app.addEventListener('click',(e)=>{//绑定 注册 订阅
        console.log('app');
        e.stopImmediatePropagation()
     },false)
  • 点击box 根据上面两个例子,我们很容易就知道,这里输出顺序为box->wrap->app

那我们来看看什么是冒泡过程

冒泡过程

冒泡过程就是在我们找到目标子容器以后,再向父容器传递的一个过程,也就是捕获事件相反的方向, 从事件触发处往window上传播,遇到注册的冒泡事件会触发

f

event.stopPropagation() || e.stopImmediatePropagation()

如果我只想要我点击的那个容器触发,其他容器不触发,那应该怎么办呢?那么我们就得用到event.stopPropagation()或e.stopImmediatePropagation()了

这两个方法都是用来阻止默认事件的传播(用在冒泡就阻止冒泡,捕获就阻止捕获)

js 复制代码
        let box = document.getElementById('box')
        box.addEventListener('mouseenter',(e)=>{
            console.log('box');
            //  e.stopPropagation()//停止传播
            e.stopImmediatePropagation()
            
        })

此时,我们点击box,就只会打印box

那么这两个方法有什么区别呢?

js 复制代码
        let box = document.getElementById('box')
        box.addEventListener('mouseenter',(e)=>{
            console.log('box');
            //阻止冒泡
            //  e.stopPropagation()//停止传播
            e.stopImmediatePropagation()
            
        })
        box.addEventListener('click',()=>{
            console.log('box2');
               
        })

我们在上面的代码中给box添加了两个点击事件,当我们点击box时,会触发,如果我们使用stopImmediatePropagation()来阻止默认事件的传播,那么我们的监听器只有一个会被触发,也就是mouseenter事件,如果使用 stopPropagation()那么两个事件都会触发...

事件委托

借助冒泡机制,将原本要添加到多个子容器上的事件添加到父容器上

html 复制代码
<!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="ul">
        <li>a</li>
        <li>b</li>
        <li>c</li>
        <li>d</li>
        <li>e</li>
    </ul>
    <script>
        let lis = document.querySelectorAll('li')
        lis.forEach((li)=>{
            li.addEventListener('click',()=>{
                console.log(li.innerText);
            })
        })
    </script>
</body>
</html>

如果我们要在ul中的每个li上添加点击事件,按照传统方法,我们可以先获取到每个li,再遍历添加点击事件,但是这种方法属实有一点low了,我们使用在父容器上添加点击事件的方法

js 复制代码
        let ul = document.getElementById('ul')
        ul.addEventListener('click',(e)=>{
            console.log(e.target.innerText);
           
        })

在 ul 元素上添加了点击事件监听器。当用户点击 ul 元素内部的任意一个子元素时,事件会冒泡到 ul 元素,并触发该监听器。

在监听器中,通过 e.target 可以获取到实际触发事件的元素。通过 e.target.innerText 可以获取到该元素的文本内容。

结尾

祝掘友们新年快乐!!!!!!!!!!

相关推荐
智码看视界5 小时前
C++智能指针全景剖析及面试20问
开发语言·c++·深度学习·面试·内存管理·智能指针
Chrischaan5 小时前
做 AI 塔罗小程序时,我为什么不让大模型自己抽牌:一次上线复盘
前端
骑着蜗牛撵大象3276 小时前
LangChain 工具调用从声明到闭环:给智能体接上真实的手脚
前端
数据掘金6 小时前
百度统计后台页面数据异常?从手动调用时机开始排查
前端
hunteritself6 小时前
10 层 4K 实时剪辑,国产工作站进入广电制作核心
大数据·前端·人工智能·深度学习·transformer
踩着两条虫6 小时前
我在浏览器里“盖”了一个村:Vue + Three.js 大屏开发踩坑记
前端·vue.js·three.js
默_笙6 小时前
🧀 让大模型的答案"流"出来:NestJS AI 模块 + SSE + RxJS 实战
javascript·人工智能
mbshqqb6 小时前
TypeScript基础教程之同步生成器
前端·javascript·typescript
嘟嘟同学和妮妮同学7 小时前
【升级】一个中国历史可视化站:皇帝时间线梳理、古代思想流派、诗词鉴赏 (2)
前端·html
暗夜行者之光7 小时前
LangGraph + MCP 实战:构建"自然语言查数据"的 ChatBI Agent
前端·后端