JavaScript中的事件代理机制你看你也会

275 阅读4分钟

前言

在JavaScript中,事件代理(Event Delegation)是一种处理事件的技术,它允许你在一个父元素上添加一个事件监听器来处理其所有子元素的事件,而不是为每个子元素单独添加事件监听器。这种方法可以极大地减少代码量和提高性能,特别是在处理大量动态生成的元素时。

在本文中,我将会为大家解读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>
</head>
<body>
    <ul>
        <li>1</li>
        <li>2</li>
        <li>3</li>
    </ul>
    
</body>
</html>

如果我想实现点击一个li就会打印该li的内容,实现方法有很多种,第一种我们直接使用'卷铺盖'走人大法,三个li我们就写三个函数,分别绑定.但是如果有200个li,岂不是要写200个函数,真要是这样写的话,包可以卷铺盖走人的.那么正常点的写法就是通过document.querySelectorAll("li")获取到所有的DOM结构,然后给每一个li都添加事件监听。

let lis = document.querySelectorAll("li");
        console.log(lis);
        lis.forEach((li,i)=>{
            li.addEventListener("click",function(){
                console.log(this.innerText);
            })
        })

除此之外还有没有更加优雅的写法呢?诶,别说还真有,诸位请看下文

事件流

在聊事件代理之前,我们先将事件流聊一聊。

<!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>
        #grand{
            width: 400px;
            height: 400px;
            background-color: rgb(67, 198, 238);
        }
        #parent{
            width: 300px;
            height: 300px;
            background-color: rgb(193, 22, 236);
        }
        #child{
            width: 200px;
            height: 200px;
            background-color: rgb(22, 236, 108);
        }
    </style>
</head>
<body>
    <div id="grand">
        <div id="parent">
            <div id="child"></div>
        </div>
    </div>
    <script>
        let grand = document.getElementById("grand")
        let parent = document.getElementById("parent")
        let child = document.getElementById("child")

        grand.addEventListener("click", function(e) {
            console.log('grand');
        })
        parent.addEventListener("click", function() {
            console.log('parent');
        })
        child.addEventListener("click", function() {
            console.log('child');
        })
    </script>
</body>
</html>

image.png 我们来看看这样一串代码,我们在每一个div都绑定了点击事件.点击蓝色区域,打印的是grand这点没有问题,但是如果我们点击紫色或者绿色区域呢?会打印什么? 我们先点击紫色区域

image.png

先打印的是parent再打印grand

我们现在点击绿色区域看看

image.png

诶嘿,打印的顺序是child,parent,grand。这是怎么回事呢?其实啊,这是JavaScript中的事件冒泡机制.对于事件冒泡机制存在三个阶段.

捕获阶段:事件从window处往目标处传播
目标阶段:在目标处触发事件
冒泡阶段:事件从目标处往window上传播

其实事件冒泡的触发流程是先从父容器往目标处传播,到达目标容器后就会先把目标容器的事件触发,再从目标容器向外传播到window.

image.png

在冒泡阶段会触发掉parentgrand的事件.所以我们看到点击绿色的div的打印结果顺序是child,parent,grand.

这里我们需要知道的是addEventListener()有第三参数,这第三个参数默认值为false也就是在捕获阶段不会触发事件,如果我们修改成true,打印结果就反过来了.

image.png

那么我们可以不可阻止事件冒泡的触发呢?这里我们使用事件参数e调用stopPropagation()就会阻止事件流传播.

image.png

还有一种方法e.stopImmediatePropagation()也可以阻止事件流测传播 +同时也会阻止同一个容器绑定多个相同的事件.

事件代理

由于事件代理依赖于事件冒泡的概念,所以我们先聊了一下事件冒泡.最后我们再来聊事件代理.事件代理就是把一个元素身上需要响应的事件,委托到另一个元素(父元素)上.

我们继续看到开篇的场景题

<!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>
        <li>1</li>
        <li>2</li>
        <li>3</li>
    </ul>
    <script>
        let ul = document.querySelector("ul")
        ul.addEventListener('click',function(e){
            console.log(e);
        })
        
    </script>
</body>
</html>

我们看看打印结果是什么

image.png

拿到的是这个ul的dom结构,我们可以通过e.target.innerText获取到对应li的值。 在这个例子中,我们没有为每个<li>元素单独添加事件监听器,而是将监听器放在了它们共同的父元素<ul>上。当用户点击任何<li>元素时,点击事件会冒泡到<ul>元素,然后我们的监听器就会被执行。通过检查event.target,我们可以确定是哪一个具体的<li>元素被点击了.

本文到此就结束了,希望对各位有所帮助!!感谢大家阅读