Coder丶L

  博客园 :: 首页 :: 博问 :: 闪存 :: 新随笔 :: 联系 :: 订阅 订阅 :: 管理 ::

  今天学到了事件冒泡和事件捕获,不得不说这里面还是有着一些小小的可能不那么为人所理解的知识点的,这里我来做一个小小的整理。

  首先先上概念,什么叫事件冒泡?什么又叫事件捕获?简单的说,事件冒泡就是结构上具有嵌套关系的元素(父子结构),对于同一类型的事件(比如click),在子元素上触发该事件会使得父元素也触发父元素自己的(如果父元素有的话)该类型的事件,来看代码:

<body>
<div id="grandfather">
    <div id="father">
        <div id="son"></div>
    </div>
</div>

<script>
    var grandfather = document.getElementById('grandfather'),
        father = document.getElementById('father'),
        son = document.getElementById('son');
    grandfather.addEventListener('click', function () {
        console.log('grandfather');
    }, false);
    father.addEventListener('click', function () {
        console.log('father');
    }, false);
    son.addEventListener('click', function () {
        console.log('son');
    }, false);
</script>
</body>

  这里我们创建了一个嵌套的三层div,并且给每个div绑定了一个点击事件。事件冒泡的意思就是当我们点击grandfather的时候,触发的是grandfather的点击事件;当我们点击father的时候,触发的会是father和grandfather的点击事件,并且触发顺序是先father再grandfather;而当我们点击son的时候,触发的会是son和father和grandfather的点击事件,并且触发顺序是先son再father最后grandfather。这就意味着冒泡是从子元素冒泡到父元素的。

  我们再来看事件捕获。事件捕获和时间冒泡相似,只不过事件的触发顺序反过来了。拿上面的代码来说,只要把每个addEventListener函数的第三个参数‘false’改成‘true’就等于从事件冒泡变成了事件捕获。改成事件捕获之后,当我们点击grandfather的时候,触发的是grandfather的点击事件;当我们点击father的时候,触发的会是father和grandfather的点击事件,并且触发顺序是先grandfather再father;而当我们点击son的时候,触发的会是son和father和grandfather的点击事件,并且触发顺序是先grandfather再father最后son。也就是说捕获是从父元素捕获到子元素的。(注意不是说点击父元素会使子元素触发相同类型的事件)

  你以为到了这里就结束了?不存在的,下面才是我真正要讲的知识点!

  考虑如下代码:

<body>
<div id="grandfather">
    <div id="father">
        <div id="son"></div>
    </div>
</div>

<script>
    var grandfather = document.getElementById('grandfather'),
        father = document.getElementById('father'),
        son = document.getElementById('son');
    
    grandfather.addEventListener('click', function () {
        console.log('grandfather Bubble');
    }, false);
    father.addEventListener('click', function () {
        console.log('father Bubble');
    }, false);
    son.addEventListener('click', function () {
        console.log('son Bubble');
    }, false);
    
    grandfather.addEventListener('click', function () {
        console.log('grandfather');
    }, true);
    father.addEventListener('click', function () {
        console.log('father');
    }, true);
    son.addEventListener('click', function () {
        console.log('son');
    }, true);
</script>
</body>

  你看到了什么?没错,这里我给同一个对象的同一种事件类型绑定了两个不同的函数,其中一个符合事件捕获模型,一个符合事件冒泡模型。这里先普及一个知识点:在一个对象的同一个事件类型上绑定了两个事件处理函数,这两个事件处理函数一个符合事件冒泡模型,一个符合事件捕获模型,那么肯定是先执行事件捕获,再执行事件冒泡。那么思考如果我点击了son,那么控制台上会怎么输出?

  你想的是不是先输出grandfather,然后father,然后son,接着son Bubble,接着father Bubble,最后grandfather Bubble?恭喜你,答错了。

  正确的结果是先输出grandfather,然后father,然后son Bubble,接着son,接着father Bubble,最后grandfather Bubble。为什么会这样?那是因为我们说先执行事件捕获,而后执行事件冒泡,但是不要忘记一点,当我们点击son的时候,son处于事件冒泡流或事件捕获流中吗?答案当然是否定的,son只是执行了我们的点击事件而已,并没有参与到事件冒泡或是事件捕获,所以按照我们编写代码的顺序,会先输出son Bubble,然后输出son。

  你看明白了吗?

posted on 2018-10-15 16:09  Coder丶L  阅读(138)  评论(1编辑  收藏  举报