深度剖析JavaScript中冒泡和捕获机制、事件代理

   JS事件传播的两种机制包括冒泡和捕获,下面将具体剖析它们之间本质的区别。


   事件冒泡: 先触发子元素的事件,再触发父元素的事件。


   创建一个 ul label 和 li label, 分别绑定一个父id 和 子 id, 再通过创建 script,去绑定各自的点击事件。



在这里插入图片描述



<!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="father">
        我是一个无序列表
        <li id="son">1个列表项</li>
    </ul>

    <script>
        document.getElementById('father').onclick = function(){
            console.log('我点击了父元素');
        }

        document.getElementById('son').onclick = function(){
            console.log('我点击了子元素');
        }

    </script>
</body>

</html>


   当我点击 "第1个列表项"后,在Console先输出的是 “我点击了子元素”, 然后是 “我点击了父元素”, 可见冒泡的执行顺序是由里向外,也就是从 li - ul - body - document - window 这样的执行顺序,就好比人扔了一块石头去河里,先是冒一个小泡,再逐个现成大的水泡这种扩散现象。因此,JS默认的点击事件就是冒泡。



在这里插入图片描述



   事件捕获: 先触发父元素的事件,再触发子元素的事件。如果要将冒泡改为捕获,需要添加监听事件。监听事件的第3个参数必须为 “true”, 默认为 false 。



在这里插入图片描述



<!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="father">
        我是一个无序列表
        <li id="son">1个列表项</li>
    </ul>

    <script>
        // document.getElementById('father').onclick = function(){
        //     console.log('我点击了父元素');
        // }

        document.getElementById('father').addEventListener('click',function(){
            console.log('我点击了父元素');
        },true);

        document.getElementById('son').onclick = function(){
            console.log('我点击了子元素');
        }

    </script>
</body>

</html>


    再点击 "第1个列表项"后,控制台先输出的是 “我点击了父元素”, 然后是 “我点击了子元素”, 可见捕获的执行顺序是由外向里,也就是从 window - documment - body - ul - li 这样的执行顺序。



在这里插入图片描述



    事件代理是指利用事件冒泡,只指定一个事件处理程序,就可以管理某一类型的所有事件。


    先复制多几个 li label



在这里插入图片描述



<!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="father">
        我是一个无序列表
        <li id="son">1个列表项</li>
        <li id="son">2个列表项</li>
        <li id="son">3个列表项</li>
        <li id="son">4个列表项</li>
        <li id="son">5个列表项</li>
    </ul>

    <script>
        // document.getElementById('father').onclick = function(){
        //     console.log('我点击了父元素');
        // }

        document.getElementById('father').addEventListener('click',function(){
            console.log('tesing for 事件代理');
        },true);

        // document.getElementById('son').onclick = function(){
        //     console.log('我点击了子元素');
        // }

    </script>
</body>

</html>


   例如然后点击 “第5个列表项”,由于冒泡作用,当点击到 li label,冒泡到 ul label 上,执行了 ul label上的点击事件,最后在 Console 输出了 “tesing for 事件代理”。



在这里插入图片描述



在这里插入图片描述



   通常父级那么多子元素,怎样去区分事件本应该是哪个子元素呢?在 function() 函数里面添加一个 event param, 稍后在Console打印这个 event 的 object



在这里插入图片描述



   例如当点击 “第4个列表项” 后,就会输出了 event 这个 object



在这里插入图片描述



   点击 “target” 继续展开后续的内容

在这里插入图片描述



   展开后,可见还有省略的内容,点击 “…” 这个省略的位置后,可以继续展示余下隐藏的内容。



在这里插入图片描述



   展开后,可见 textContent : “第4个列表项”



在这里插入图片描述



   添加判断条件为 点击 "第4个列表项"时,才会打印 “tesing for 事件代理”, 点击其它元素没有任何内容输出。



在这里插入图片描述



<!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="father">
        我是一个无序列表
        <li id="son">1个列表项</li>
        <li id="son">2个列表项</li>
        <li id="son">3个列表项</li>
        <li id="son">4个列表项</li>
        <li id="son">5个列表项</li>
    </ul>

    <script>
        // document.getElementById('father').onclick = function(){
        //     console.log('我点击了父元素');
        // }

        document.getElementById('father').addEventListener('click',function(event){
            if (event.target.textContent === "第4个列表项"){
            console.log('tesing for 事件代理');
            };
            // console.log(event);
        },true);

        // document.getElementById('son').onclick = function(){
        //     console.log('我点击了子元素');
        // }

    </script>
</body>

</html>


   怎么取消冒泡或者捕获 ? 通过 event.stopPropagation() 方法可以实现。



在这里插入图片描述



<!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="father">
        我是一个无序列表
        <li id="son">1个列表项</li>
        <!-- <li id="son">2个列表项</li>
        <li id="son">3个列表项</li>
        <li id="son">4个列表项</li>
        <li id="son">5个列表项</li> -->
    </ul>

    <script>
        // document.getElementById('father').onclick = function(){
        //     console.log('我点击了父元素');
        // }

        // document.getElementById('father').addEventListener('click',function(event){
        // //     if (event.target.textContent === "第4个列表项"){
        // //     console.log('tesing for 事件代理');
        // //     };
        // //     // console.log(event);
        // // },true);

        // document.getElementById('son').onclick = function(){
        //     console.log('我点击了子元素');
        // }

        document.getElementById('father').addEventListener('click',function(event){
            console.log('testing for click father element');
        });

        document.getElementById('son').addEventListener('click',function(event){
            console.log('testing for click son element');
            event.stopPropagation();
        });


    </script>
</body>

</html>


   再次点击 “第1个列表项” 后,只执行子元素输出 “testing for click son element”,不再执行父元素, 也就是不再输出 “testing for click father element”, 取消了冒泡。



在这里插入图片描述

  • 11
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值