JavaScript 事件冒泡和事件捕获

一、事件冒泡和事件捕获的区别

  • 事件冒泡和事件捕捉都是浏览器事件的传递机制

  • 事件冒泡:当给父子元素的同一事件绑定方法的时候,触发子元素身上的事件,执行完毕之后,会触发父级元素相同的事件,就是触发的顺序是由DOM树的下层到DOM树的最上面,这种机制叫事件冒泡,取消事件冒泡可以用event.stopProPagation

  • 事件捕获:事件捕获的思想是指不太具体的节点应该更早的接收到事件,而最具体的节点应该最后接收到事件,给父子元素用 addeventlistener()绑定同一事件时,并且第三个参数改为 true ,当触发子元素身上的事件时,先触发父元素,然后在传递给子元素,这种传播机制叫事件捕获

二、事件冒泡

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body onclick="bodyClick()">

    <div onclick="divClick()">
        <button onclick="btn()">
            <p onclick="p()">点击冒泡</p>
        </button>
    </div>
    <script>
       
       function p(){
          console.log('p标签被点击')
       }
        function btn(){
            console.log("button被点击")
        }
         function divClick(event){
             console.log('div被点击');
         }
        function bodyClick(){
            console.log('body被点击')
        }

    </script>

</body>
</html>
复制代码

点击p元素后

image.png

三、事件捕获

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>

<div>
    <button>
        <p>点击捕获</p>
    </button>
</div>
<script>
    var oP=document.querySelector('p');
    var oB=document.querySelector('button');
    var oD=document.querySelector('div');
    var oBody=document.querySelector('body');

    oP.addEventListener('click',function(){
        console.log('p标签被点击')
    },true);

    oB.addEventListener('click',function(){
        console.log("button被点击")
    },true);

    oD.addEventListener('click',  function(){
        console.log('div被点击')
    },true);

    oBody.addEventListener('click',function(){
        console.log('body被点击')
    },true);

</script>

</body>
</html>
复制代码

点击p元素后

image.png

四、DOM事件流

DOM2级事件规定的事件流包含3个阶段,事件捕获阶段、处于目标阶段、事件冒泡阶段。首先发生的事件捕获为截获事件提供机会,然后是实际的目标接收事件,最后一个阶段是事件冒泡阶段,可以在这个阶段对事件做出响应

而在DOM事件流中,事件的目标在捕获阶段不会接收到事件,这意味着在捕获阶段事件从document到<button>就停止了,下个阶段是处于目标阶段,于是事件在<button>上发生,并在事件处理中被看成冒泡阶段的一部分,然后,冒泡阶段发生,事件又传播回document

<!DOCTYPE html>
<html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Title</title>
    </head>
    <body>
        <button id="btn">DOM事件流</button>
        <script>
            var btn=document.getElementById("btn");

            btn.onclick=function(event){
                console.log("btn 处于目标阶段");
            };

            document.body.addEventListener("click",function(event){
                console.log("event bubble 事件冒泡");
            },false);

            document.body.addEventListener("click",function(event){
                console.log("event catch 事件捕获");
            },true);
        </script>

    </body>
</html>
复制代码

打印的顺序分别是:

  • event catch 事件捕获
  • btn 处于目标阶段
  • event bubble 事件冒泡

image.png

五、DOM 2级事件流

DOM 2级事件定义了两方法:用于处理添加事件和删除事件的操作:

  1. 添加事件 addEventListener()    
  2. 删除事件  removeEventListener()

所有DOM节点中都包含这两个方法,并且他们都包含3个参数: 

  1. 要处理的事件类型(例如:click,mouseover,dbclick…..)
  2. 事件处理的函数,可以为匿名函数,也可以为命名函数(但如果需要删除事件,必须是命名函数)
  3. 一个布尔值,代表是处于事件冒泡阶段处理还是事件捕获阶段处理(true:表示在捕获阶段调用事件处理程序;false:表示在冒泡阶段调用事件处理程序)

使用DOM 2级事件处理程序的主要好处是可以添加多个事件处理程序,事件处理会按照他们的顺序触发,通过 addEventListener 添加的事件只能用 removeEventListener 来移除,移除时传入的参数与添加时使用的参数必须相同,这也意味着添加的匿名函数将无法移除(注意:第三个参数都是默认false,是指在冒泡阶段处理事件,大多数情况下,都是将事件处理程序添加到事件的冒泡阶段,这样可以最大限度的兼容各个浏览器)

DOM 2级事件添加方式

//这是一个DOM 2级事件 添加事件最简单的方式(此时添加的是一个匿名函数)
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>

    <button>按钮</button>
    <script>
        var btn=document.querySelector('button');
        btn.addEventListener('click',function(){
            console.log('我是按钮')
        },false)   
        // 当第三个参数不写时,也是默认为false(冒泡阶段处理事件)
    </script>

</body>
</html>

// 命名函数
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>

    <button>按钮</button>
    <script>
        var btn=document.querySelector('button');
        btn.addEventListener('click',foo,false);
        function foo(){
            console.log('我是按钮')
        }           
        // 其实操作就是把写在里面的函数拿到了外面,而在原来的位置用函数名来代替
    </script>
</body>
</html>
复制代码
  • 添加两个事件时候的执行顺序
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>

    <button>按钮</button>
    <script>
        var btn=document.querySelector('button');
        
        // 第一个事件
        btn.addEventListener('click',foo,false);
        function foo(){
            console.log('我是按钮')
        }        
        //第二个事件
        btn.addEventListener('click',newFoo,false);
        function newFoo(){
            console.log('我是新按钮')
        }
    </script>
</body>
</html>
复制代码

image.png
结论:添加两个事件是可以的,事件的顺序就是按照程序写的顺序执行的

  • 试试DOM 0级事件处理程序
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
    <button onclick="foo()"  onclick="newFoo()">按钮</button>
    <script>
        function foo(){
            console.log('我是按钮')
        }
        function newFoo(){
            console.log('我是新按钮')
        }
    </script>
</body>
</html>
复制代码

后台只打印了“我是按钮”,说明DOM 0级事件处理程序只执行了第一个事件,第二个事件被忽略了

© 版权声明
THE END
喜欢就支持一下吧
点赞0 分享