DOM事件流,冒泡 | 捕获 | 委托 ,详解

(一)DOM事件流

① 定义

DOM事件流包括三个阶段

  1. 捕获阶段
  2. 目标阶段
  3. 冒泡阶段

首先发生的是事件捕获,为截获事件提供了机会。然后是实际的目标接收到事件。最后一个是冒泡阶段,在这个阶段对事件做出响应

事件发生时会在元素节点之间按照特定的顺序传播,这个传播的过程就是DOM事件流
简单的说:事件的传播过程即DOM事件流

② 图解

在这里插入图片描述
在这里插入图片描述

③ 历史

当浏览器发展到第四代时(IE4及Netscape Communicator4),浏览器开发团队遇到了一个很有意思的问题:页面的哪一部分会拥有某个特定的事件?要明白这个问题问的是什么,可以想象画在一张纸上的一组同心圆。如果你把手指放在圆心上,那么你的手指指向的不是一个圆,而是纸上所有的圆,两家公司的浏览器开发团队在看待浏览器事件方面还是一致的。如果你单击了某个按钮,他们都认为单击事件不仅仅发生在按钮上。换句话说,在单机按钮的同时,你也单击了按钮的容器元素,甚至也单击了整个页面。
事件流描述的是从页面中接受事件的顺序。但有意思的是,IE 和 Netscape 开发团队居然提出了差不多完全相反的概念,IE的事件流是冒泡流,而Netscape Communicator的事件流是事件捕获流。

(摘自《JavaScript高级程序设计》)

下面我用实例展现一下冒泡和捕获的不同之处。

(二)冒泡

在这里插入图片描述
我给分别给div、section、body、html、window设置了点击事件,然后只点击了div,现在我们来分析一下此时的事件传播过程

首先,进入捕获阶段,实际的目标元素(div)在捕获阶段不会接收到事件。这意味着在捕获阶段,事件从window → html → body → section就停止了。下一个阶段是目标阶段,于是事件在div上发生,并在事件处理中被看成冒泡的一部分。然后事件冒泡发生,事件又传播回window。所以我们看到了下述的事件执行顺序。

事件的执行顺序是:
小 → 大
div → section → body → html → window

扫描二维码关注公众号,回复: 11189992 查看本文章

下面贴上代码(css部分就不贴了,问题不大)

html部分

<body>
    <p>body</p>
    <section>
       <p>父盒子</p> 
        <div>子盒子</div>
    </section>
</body>

JS部分

    <script>
        var oSection = document.querySelector("section");
        var oDiv = document.querySelector("div");
        var oHtml = document.documentElement;
        var oBody = document.body;
        oDiv.addEventListener("click",function(){
            alert("我是子盒子")
        })
        oSection.addEventListener("click",function(){
            alert("我是父盒子")
        })
        oHtml.addEventListener("click",function(){
            alert("我是html")
        })
        oBody.addEventListener("click",function(){
            alert("我是body")
        })
        window.addEventListener("click",function(){
            alert("我是window")
        })
    </script>

(三)捕获

事件捕获如何触发呢?
这时需要用到 addEventListener( )方法的第三个参数(默认为false,即冒泡阶段),将第三个参数改为true,表示将此事件改为捕获阶段。
( 如果不了解addEventListener( )方法的可以 查看文档

接下来我们看一下事件在捕获阶段的触发顺序:

根据上面的代码,我们先把父盒子section的点击事件变为捕获阶段

    oSection.addEventListener("click",function(){
        alert("我是父盒子")
    },true)

看看效果:
在这里插入图片描述
首先,进入捕获阶段,实际的目标元素(div)在捕获阶段不会接收到事件。但我们把section的点击事件变为了捕获阶段发生,section的点击事件被捕获了,所以最先触发。 下一个阶段是目标阶段,于是事件在div上发生,并在事件处理中被看成冒泡的一部分。然后事件冒泡发生,事件又传播回window。所以我们才看到了下述的事件执行顺序。

此时的执行顺序是:

section → div → body → html → window

现在,我们将所有的事件都变成捕获阶段,看看效果:在这里插入图片描述
此时的执行顺序是:

window → html → body → section → div

与冒泡阶段的执行顺序完全相反。

(四)在不同的阶段执行事件

多数支持DOM事件流的浏览器都实现了一种特定的行为:即使 “DOM2级事件” 规范明确要求捕获阶段不会涉及事件目标,但IE9,Safari,Chrome,Firefox 和 Opera9.5 以及更高版本都会在事件捕获阶段触发事件对象上的事件。结果就是有两个机会在目标对象上操作事件。
(摘自《JavaScript高级程序设计》)

想要了解HTML,DOM0,DOM2事件处理函数可以查看此文章

下面通过实例实践一下:

首先,让所有的事件在冒泡阶段才触发,然后给section绑定两个点击事件,一个在捕获阶段,一个在冒泡阶段

  oSection.addEventListener("click",function(){
        alert("我是父盒子,我在捕获阶段被触发了")
    },true)//捕获阶段
    oSection.addEventListener("click",function(){
        alert("我是父盒子,我在冒泡阶段被触发了")
    })

看看效果:

在这里插入图片描述
可以看到,section的两个点击事件都触发了,一个在捕获阶段,一个在冒泡阶段。

(五)提高内存和性能 – 事件委托

对 “事件处理程序过多” 问题的解决方案就是事件委托。事件委托利用了事件冒泡,只指定一个事件处理程序,就可以管理某一项类型的所有事件。例如,click事件会一直冒泡到window层次。也就是说,我们可以为整个页面指定一个onclick事件,而不必给每个可单击的元素分别添加事件
(事件处理程序指响应某个事件的函数)

下面看看效果和代码:

① 实例

在这里插入图片描述

JS代码

  <script>
    window.addEventListener("click", function (e) {
        switch (e.target.className) {//我事先给每个元素设定了一个专属class
            case "html":
                alert("我是html");
                break;
            case "body":
                alert("我是body");
                break;
            case "section":
                alert("我是父盒子");
                break;
            case "div":
                alert("我是子盒子");
                break;
        }
    })
</script>

上述代码中,我们使用事件委托只为window添加了一个onclick事件处理函数,由于所有的元素都是window的子节点,而且它们的事件会冒泡,所以单击事件最终会被这个函数处理,然后通过检测属性的className来检测是哪个元素被点击,从而做出不同的动作。

上述代码中还用到了event事件对象,target返回触发此事件的元素。也就是说,谁触发了window的点击事件,target就是谁。

② 优点

上述代码与前面未使用事件委托的代码比一比,会发现这段代码的事前消耗更低,因为不需要取得DOM元素(或者只需要取得一个DOM元素),只添加了一个事件处理程序。虽然对于用户来说最终的结果相同,但是这种技术需要占用的内存更少。所有用到按钮的事件(多鼠标事件和键盘事件)都适合采用事件委托技术。

这样做与采取传统的做法相比具有如下优点:

  • window对象很快就可以访问,只要可单击的元素呈现在页面上,就可以立即具备适当的功能
  • 在页面中设置事件处理程序所需的事件更少。只添加一个事件处理程序所需的DOM引用更少,所花的时间也更少
  • 整个页面占据的内存空间更少,能够提升整体性能。

我的与此文章相关的文章:
1.DOM事件处理函数、DOM0,DOM2的优缺点及IE兼容

结语:若文章有错误的地方,烦请在评论区指出。当然,我会不定时的重新编辑写过的文章,查错及优化,希望能将最好的文章展现给读者。

原创文章 8 获赞 69 访问量 2547

猜你喜欢

转载自blog.csdn.net/LeslieCheung_/article/details/106005365