专业编程基础技术教程

网站首页 > 基础教程 正文

事件的捕获和冒泡(什么是事件冒泡和事件捕获,区别是什么)

ccvgpt 2024-07-24 11:06:38 基础教程 10 ℃

参考API地址:https://developer.mozilla.org/zh-CN/docs/Web/API/EventTarget/addEventListener#%E8%AF%AD%E6%B3%95

添加一个监听事件,首先我们看一下API的语法如下

事件的捕获和冒泡(什么是事件冒泡和事件捕获,区别是什么)

addEventListener(type, listener);
addEventListener(type, listener, options);
addEventListener(type, listener, useCapture);

常用到的是第一个和第三个因为,useCapture默认值是false

useCapture 可选

一个布尔值,表示在 DOM 树中注册了 listener 的元素,是否要先于它下面的 EventTarget 调用该 listener。当 useCapture(设为 true)时,沿着 DOM 树向上冒泡的事件不会触发 listener。当一个元素嵌套了另一个元素,并且两个元素都对同一事件注册了一个处理函数时,所发生的事件冒泡和事件捕获是两种不同的事件传播方式。事件传播模式决定了元素以哪个顺序接收事件。进一步的解释可以查看 DOM Level 3 事件及 JavaScript 事件顺序文档。如果没有指定,useCapture 默认为 false。

这个值的作用有什么用呢?下面我开始了我的摸索和见解。废话不多说开始上demo演示。

<!DOCTYPE html>
<html lang="zh-CN>
<head>
    <meta charset=" UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<style>
    div {
        padding: 15px;
        border: 1px solid #e5f3fe;
        position: relative;
        overflow: hidden;
    }

    span {
        background-color: #f2f1f1;
        padding: 8px 15px;
        margin: 15px;
        display: inline-block;
    }

    .description {
        font-size: 22px;
        font-weight: 600;
    }
</style>
</head>

<body>
    <p class="description">
        ok 兄弟你每次点击“节点2” 就会发现这个参数的不同点了。是不是 它的触发顺序出现了不同 对 就是这样的。
    </p>
    <label>
        <input checked onchange="radioChange(this.value)" name="useCapture" type="radio" id="radio2" value="false" />
        useCapture=false
    </label>
    <label>
        <input onchange="radioChange(this.value)" name="useCapture" type="radio" id="radio1" value="true" />
        useCapture=true
    </label>
    
    <div title="节点1">
        <span>节点1</span>
        <div title="节点2">
            <span>节点2</span>
        </div>
    </div>

    <script>
        //  个人总结:false的话 就是事件冒泡了 从子元素到父元素
        // true的话   就是事件捕获 从父到子!
        let useCapture = false
        // 添加事件
        function bindEvent() {
            const targets = document.querySelectorAll('div')
            targets.forEach(element => {
                element.addEventListener('click', handleClick, useCapture)
            });
        }
        // 移除事件
        function removeEvent() {
            const targets = document.querySelectorAll('div')
            targets.forEach(element => {
                element.removeEventListener('click', handleClick, useCapture)
            });
        }
        // div click handle
        function handleClick(event){
            // event.stopPropagation()
            alert(this.getAttribute('title'))
        }
        // 处理 radio change
        function radioChange(checked) {
            removeEvent()             
            console.log('radioChange')
            console.log(checked)
            useCapture = checked=="true" ? true : false
            bindEvent()
        }
        // 执行绑定事件
        bindEvent()
    </script>
</body>

</html>

demo运行起来是这样的效果


我们发现当div或者出发事件的元素存在嵌套的情况下,这个是控制事件的执行顺序的。useCapture=false默认是冒泡,冒泡怎么理解呢就是水里的泡泡往上冒么,那么就是从子元素王父元素执行。

Capture=true就是捕获点击一下先相应父级元素的事件,然后传递到子元素。也就是先执行父的事件在执行子的事件。

还有一个就是阻止事件冒泡的 event.stopPropagation();

API文档地址:https://developer.mozilla.org/zh-CN/docs/Web/API/Event/stopPropagation

我们改动一下我们的DEMO再看看

<!DOCTYPE html>
<html lang="zh-CN>
<head>
    <meta charset=" UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<style>
    div {
        padding: 15px;
        border: 1px solid #e5f3fe;
        position: relative;
        overflow: hidden;
    }

    span {
        background-color: #f2f1f1;
        padding: 8px 15px;
        margin: 15px;
        display: inline-block;
    }

    .description {
        font-size: 22px;
        font-weight: 600;
    }
</style>
</head>

<body>
    <p class="description">
        ok 兄弟你每次点击“节点2” 就会发现这个参数的不同点了。是不是 它的触发顺序出现了不同 对 就是这样的。
    </p>
    <label>
        <input checked onchange="radioChange(this.value)" name="useCapture" type="radio" id="radio2" value="false" />
        useCapture=false
    </label>
    <label>
        <input onchange="radioChange(this.value)" name="useCapture" type="radio" id="radio1" value="true" />
        useCapture=true
    </label>
    
    <div title="节点1">
        <span>节点1</span>
        <div title="节点2">
            <span>节点2</span>
        </div>
    </div>

    <script>
        //  个人总结:false的话 就是事件冒泡了 从子元素到父元素
        // true的话   就是事件捕获 从父到子!
        let useCapture = false
        // 添加事件
        function bindEvent() {
            const targets = document.querySelectorAll('div')
            targets.forEach(element => {
                element.addEventListener('click', handleClick, useCapture)
            });
        }
        // 移除事件
        function removeEvent() {
            const targets = document.querySelectorAll('div')
            targets.forEach(element => {
                element.removeEventListener('click', handleClick, useCapture)
            });
        }
        // div click handle
        function handleClick(event){
            event.stopPropagation()
            alert(this.getAttribute('title'))
        }
        // 处理 radio change
        function radioChange(checked) {
            removeEvent()             
            console.log('radioChange')
            console.log(checked)
            useCapture = checked=="true" ? true : false
            bindEvent()
        }
        // 执行绑定事件
        bindEvent()
    </script>
</body>

</html>

发现事件触发了以后,就不再冒泡或者继续往子元素传递了。这是我的理解和简介欢迎大家拍砖。

最近发表
标签列表