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

浅聊一下

试想一下,我们有三个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 可以获取到该元素的文本内容。

结尾

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

相关推荐
袁煦丞13 分钟前
【私人导航员+内网穿透神器】Sun-Panel × cpolar让NAS变身你的数字管家:cpolar内网穿透实验室第564个成功挑战
前端·程序员·远程工作
爱吃的强哥13 分钟前
Electron_Vue3 自定义系统托盘及退出二次确认
前端·javascript·electron
袁煦丞19 分钟前
开启SSH后,你的NAS竟成私有云“变形金刚”:cpolar内网穿透实验室第645个成功挑战
前端·程序员·远程工作
IT_陈寒19 分钟前
SpringBoot 3.2新特性实战:这5个隐藏功能让我开发效率提升50%
前端·人工智能·后端
申阳1 小时前
2小时个人公司:一个全栈开发的精益创业之路
前端·后端·程序员
用户9873824581011 小时前
5. view component
前端
技术小丁1 小时前
零依赖!教你用原生 JS 把 JSON 数组秒变 CSV 文件
前端·javascript
古一|1 小时前
Vue路由两种模式深度解析+Vue+SpringBoot生产部署全流程(附Nginx配置)
javascript·vue.js·nginx
Crystal3281 小时前
原生 Vue + UniApp 的小程序或 App 项目里如何判断用户是否为首次下载应用
前端·vue.js
时间的情敌2 小时前
基于 Vue3 及TypeScript 项目后的总结
前端·vue.js·typescript