前端面试必会DOM事件流、冒泡 、 捕获 、 委托

来源:程序思维浏览:2398次
(一)DOM事件流

① 定义

DOM事件流包括三个阶段:

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

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

② 图解



③ 历史

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

(二)冒泡



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

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

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

下面贴上代码(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,表示将此事件改为捕获阶段。

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

根据上面的代码,我们先把父盒子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 以及更高版本都会在事件捕获阶段触发事件对象上的事件。结果就是有两个机会在目标对象上操作事件。

下面通过实例实践一下:

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

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

看看效果:



可以看到,section的两个点击事件都触发了,一个在捕获阶段,一个在冒泡阶段。

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

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

下面看看效果和代码:

① 实例



<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引用更少,所花的时间也更少
整个页面占据的内存空间更少,能够提升整体性能。
精品好课
HTML5视频播放器video开发教程
适用人群1、有html基础2、有css基础3、有javascript基础课程概述手把手教你如何开发属于自己的HTML5视频播放器,利用mp4转成m3u8格式的视频,并在移动端和PC端进行播放支持m3u8直播格式,兼容...
HTML5基础入门视频教程易学必会
HTML5基础入门视频教程,教学思路清晰,简单易学必会。适合人群:创业者,只要会打字,对互联网编程感兴趣都可以学。课程概述:该课程主要讲解HTML(学习HTML5的必备基础语言)、CSS3、Javascript(学习...
VUE2+VUE3视频教程从入门到精通(全网最全的Vue课程)
VUE是目前最火的前端框架之一,就业薪资很高,本课程教您如何快速学会VUE+ES6并应用到实战,教你如何解决内存泄漏,常用UI库的使用,自己封装组件,正式上线白屏问题,性能优化等。对正在工作当中或打算学习VUE高薪就...
React实战视频教程仿京东移动端电商
React是前端最火的框架之一,就业薪资很高,本课程教您如何快速学会React并应用到实战,对正在工作当中或打算学习React高薪就业的你来说,那么这门课程便是你手中的葵花宝典。
jQuery视频教程从入门到精通
jquery视频教程从入门到精通,课程主要包含:jquery选择器、jquery事件、jquery文档操作、动画、Ajax、jquery插件的制作、jquery下拉无限加载插件的制作等等......
Vue2+Vue3+ES6+TS+Uni-app开发微信小程序从入门到实战视频教程
2021年最新Vue2+Vue3+ES6+TypeScript和uni-app开发微信小程序从入门到实战视频教程,本课程教你如何快速学会VUE和uni-app并应用到实战,教你如何解决内存泄漏,常用UI库的使用,自己...
最新完整React视频教程从入门到精通纯干货纯实战
React是目前最火的前端框架,就业薪资很高,本课程教您如何快速学会React并应用到实战,教你如何解决内存泄漏,常用UI库的使用,自己封装组件,正式上线白屏问题,性能优化等。对正在工作当中或打算学习React高薪就...
最新完整React+VUE视频教程从入门到精,企业级实战项目
React和VUE是目前最火的前端框架,就业薪资很高,本课程教您如何快速学会React和VUE并应用到实战,教你如何解决内存泄漏,常用库的使用,自己封装组件,正式上线白屏问题,性能优化等。对正在工作当中或打算学习Re...
收藏
扫一扫关注我们