DOM事件流

146 阅读3分钟

一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第13天,点击查看活动详情

DOM事件流

概述

事件流描述的是从页面中接收事件的顺序。
事件发生时会在元素节点之间按照特定的顺序传播,这个传播过程即DOM事件流

比如我们给一个div注册了点击事件,触发事件时会经理如下过程:

image.png

DOM事件流3个阶段

DOM事件流的3个阶段分别是:

  1. 事件捕获阶段
  2. 处于目标阶段
  3. 事件冒泡阶段

整个流程:
当事件被触发时,首先经理的阶段是捕获阶段,是Document节点自上而下向目标节点传播的过程,所有经过的节点都会触发相对应的事件。
随后事件到了具体元素身上也就是目标阶段,在具体元素上发生,它会被看作是冒泡阶段的一部分
冒泡阶段是从目标节点往上,是一个向Document节点传播的过程

一些注意事项

1 . JS代码中只能执行 捕获阶段或者冒泡阶段其中的一个阶段

2 . onclick 和 attachEvent(ie)只能得到冒泡阶段

3 . 捕获阶段 如果addEventListener第三个参数是true,则处于捕获阶段 document -> html -> body -> father -> son

案例

        <div class="father">
            <div class="son">son</div>
        </div>
        var son = document.querySelector('.son');
        var father = document.querySelector('.father');
        son.addEventListener('click', function () {
            alert('son');
        }, true);

因为当前捕获阶段只有son盒子绑定了事件,所以从document一直检索到son盒子时,只有son盒子会触发事件。

image.png
那如果这个案例的father也绑定了事件呢

        father.addEventListener('click', function () {
            alert('father');
        }, true);

那么就会按照捕获顺序,先执行了father的事件再执行了son 的事件

image.png

image.png

4 . 冒泡阶段 如果addEventListener第三个参数是false或者没有参数,则处于冒泡阶段 son -> father -> body ->html -> document
将上面事件监听方法中的参数true删掉或者换成false,就是冒泡阶段了,执行顺序是先从son开始检索一直到document,所以会先触发son 再触发father

阻止事件冒泡

实际开发中我们很少使用事件捕获,我们更关注事件冒泡。 而有些事件是没有冒泡的,比如onblur、onfocus、onmouseleave。由于事件冒泡本身的特性,会带来坏处也会带来好处,所以需要我们灵活掌握。

见如下场景:
有时候我们执行完具体对象就不想让它再向上冒泡传播了,不然会执行其他也有绑定事件的对象,所以我们需要阻止冒泡。阻止冒泡 dom推荐的标准 stopPropagation()
案例:

    <div class="father">
        <div class="son">son</div>
    </div>
        var son = document.querySelector('.son');    
        son.addEventListener('click', function (e) {
            alert('son');
            e.stopPropagation();
        }, false);
        
        var father = document.querySelector('.father');
        father.addEventListener('click', function () {
            alert('father');
        }, false);
       
        
        document.addEventListener('click', function () {
            alert('document');
        }, false);
        

注意: 这个案例中,我们只给了son阻止了冒泡,并没有给father也阻止冒泡,所以点击father的时候它还是会向上冒泡。

同样的,stopPropagation()方法也有兼容性问题,ie678不支持,在ie678中只能使用事件对象的cancelBubble属性!
下面是一个兼容性方案:

         if (e && e.stopPropagation) { // 逻辑中断
             e.stopPropagation();
         } else {
             window.event.cancelBubble = true;
         }