DOM 事件的传播机制

前端面试大全·DOM 事件的传播机制

🌟经典真题

🌟事件与事件流

事件流

事件冒泡流

事件捕获流

标准 DOM 事件流

🌟事件委托

🌟真题解答

🌟总结


🌟经典真题

  • 谈一谈事件委托以及冒泡原理

🌟事件与事件流

事件最早是在 IE3 和 NetscapeNavigator2 中出现的,当时是作为分担服务器运算负担的一种手段。

要实现和网页的互动,就需要通过 JavaScript 里面的事件来实现。

每次用户与一个网页进行交互,例如点击链接,按下一个按键或者移动鼠标时,就会触发一个事件。我们的程序可以检测这些事件,然后对此作出响应。从而形成一种交互。

这样可以使我们的页面变得更加的有意思,而不仅仅像以前一样只能进行浏览。

在早期拨号上网的年代,如果所有的功能都放在服务器端进行处理的话,效率是非常低的。

所以 JavaScript 最初被设计出来就是用来解决这些问题的。通过允许一些功能在客户端处理,以节省到服务器的往返时间。

JavaScript 中采用一个叫做事件监听器的东西来监听事件是否发生。这个事件监听器类似于一个通知,当事件发生时,事件监听器会让我们知道,然后程序就可以做出相应的响应。

通过这种方式,就可以避免让程序不断地去检查事件是否发生,让程序在等待事件发生的同时,可以继续做其他的任务。

事件流

当浏览器发展到第 4 代时(IE4 及 Netscape4),浏览器开发团队遇到了一个很有意思的问题:页面的哪一部分会拥有某个特定的事件?

想象在一张纸上的一组同心圆。如果把手指放在圆心上,那么手指指向的不是一个圆,而是纸上的所有圆。

好在两家公司的浏览器开发团队在看待浏览器事件方面还是一致的。

如果单击了某个按钮,他们都认为单击事件不仅仅发生在按钮上,甚至也单击了整个页面。

但有意思的是,IE 和 Netscape 开发团队居然提出了差不多是完全相反的事件流的概念。

IE 的事件流是事件冒泡流,而 Netscape 的事件流是事件捕获流。

事件冒泡流

IE 的事件流叫做事件冒泡(event bubbling),即事件开始时由最具体的元素(文档中嵌套层次最深的那个节点)接收,然后逐级向上传播到较为不具体的节点(文档)。

以下列 HTML 结构为例,来说明事件冒泡。如下:

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

如果单击了页面中的 div 元素,那么这个 click 事件沿 DOM 树向上传播,在每一级节点上都会发生,按照如下顺序进行传播:

  1. div
  2. body
  3. html
  4. document

所有现代浏览器都支持事件冒泡,但在具体实现在还是有一些差别。

IE9、Firefox、Chrome、Safari 将事件一直冒泡到 window 对象。

我们可以通过下面的代码,来查看文档具体的冒泡顺序,示例如下:

<div id="box" style="height:100px;width:300px;background-color:pink;"></div>
<button id="reset">还原</button>
// IE8 以下浏览器返回 div body html document
// 其他浏览器返回 div body html document window
reset.onclick = function () {history.go();
}
box.onclick = function () {box.innerHTML += 'div\n';
}
document.body.onclick = function () {box.innerHTML += 'body\n';
}
document.documentElement.onclick = function () {box.innerHTML += 'html\n';
}
document.onclick = function () {box.innerHTML += 'document\n';
}
window.onclick = function () {box.innerHTML += 'window\n';
}

在上面的示例中,我们为 div 以及它的祖先元素绑定了点击事件,由于事件冒泡的存在,当我们点击 div 时,所有祖先元素的点击事件也会被触发。

如下图所示:

事件捕获流

Netscape Communicator 团队提出的另一种事件流叫做事件捕获(event captruing)。

事件捕获的思想是不太具体的节点应该更早接收到事件,而最具体的节点应该最后接收到事件。

事件捕获的思想是在事件到达预定目标之前就捕获它。

以同样的 HTML 结构为例来说明事件捕获,如下:

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

在事件捕获过程中,document 对象首先接收到 click 事件,然后事件沿 DOM 树依次向下,一直传播到事件的实际目标,即 div 元素:

  1. document
  2. html
  3. body
  4. div

IE9、Firefox、Chrome、Safari 等现代浏览器都支持事件捕获,但是也是从 window 对象开始捕获。

下面我们来演示一个事件捕获流的示例:

<div id="box" style="height:100px;width:300px;background-color:pink;"></div>
<button id="reset">还原</button>
// IE8 以下浏览器不支持
// 其他浏览器返回 window document html body div
reset.onclick = function () {history.go();
}
box.addEventListener('click', function () {box.innerHTML += 'div\n'
}, true)
document.body.addEventListener('click', function () {box.innerHTML += 'body\n';
}, true);
document.documentElement.addEventListener('click', function () {box.innerHTML += 'html\n';
}, true);
document.addEventListener('click', function () {box.innerHTML += 'document\n';
}, true);
window.addEventListener('click', function () {box.innerHTML += 'window\n';
}, true);

在上面的示例中,我们为 div 以及它所有的祖先元素绑定了点击事件,使用的 addEventListener 的方式来绑定的事件,并将第 2 个参数设置为了 true 表示使用事件捕获的方式来触发事件。

效果如下图所示:

标准 DOM 事件流

DOM 标准采用的是捕获 + 冒泡的方式。

两种事件流都会触发 DOM 的所有对象,从 document 对象开始,也在 document 对象结束。

换句话说,起点和终点都是 document 对象(很多浏览器可以一直捕获 + 冒泡到 window 对象)

DOM 事件流示意图:

DOM 标准规定事件流包括三个阶段:事件捕获阶段处于目标阶段事件冒泡阶段

  • **事件捕获阶段:**实际目标 div 在捕获阶段不会触发事件。捕获阶段从 window 开始,然后到 document、html,最后到 body 意味着捕获阶段结束。

  • **处于目标阶段:**事件在 div 上发生并处理,但是本次事件处理会被看成是冒泡阶段的一部分。

  • **冒泡阶段:**事件又传播回文档。

🌟事件委托

上面介绍了事件冒泡流,事件冒泡一个最大的好处就是可以实现事件委托。

事件委托,又被称之为事件代理。在 JavaScript 中,添加到页面上的事件处理程序数量将直接关系到页面整体的运行性能。导致这一问题的原因是多方面的。

首先,每个函数都是对象,都会占用内存。内存中的对象越多,性能就越差。其次,必须事先指定所有事件处理程序而导致的 DOM 访问次数,会延迟整个页面的交互就绪时间。

对事件处理程序过多问题的解决方案就是事件委托。

事件委托利用了事件冒泡,只指定一个事件处理程序,就可以管理某一类型的所有事件。

例如,click 事件会一直冒泡到 document 层次。也就是说,我们可以为整个页面指定一个 onclick 事件处理程序,而不必给每个可单击的元素分别添加事件处理程序。

举一个具体的例子,例如现在我的列表项有如下内容:

<ul id="color-list"><li>red</li><li>yellow</li><li>blue</li><li>green</li><li>black</li><li>white</li>
</ul>

如果我们想把事件监听器绑定到所有的 li 元素上面,这样它们被单击的时候就弹出一些文字,为此我们需要给每一个元素来绑定一个事件监听器。

虽然上面的例子中好像问题也不大,但是想象一下如果这个列表有 100 个元素,那我们就需要添加 100 个事件监听器,这个工作量还是很恐怖的。

这个时候我们就可以利用事件代理来帮助我们解决这个问题。

将事件监听器绑定到父元素 ul 上,这样即可对所有的 li 元素添加事件,如下:

var colorList = document.getElementById("color-list");
colorList.addEventListener("click",function(){alert("Hello");
})

现在我们单击列表中的任何一个 li 都会弹出东西,就好像这些 li 元素就是 click 事件的目标一样。

并且如果我们之后再为这个 ul 添加新的 li 元素的话,新的 li 元素也会自动添加上相同的事件。

但是,这个时候也存在一个问题,虽然我们使用事件代理避免了为每一个 li 元素添加相同的事件,但是如果用户没有点击 li,而是点击的 ul,同样也会触发事件。

这也很正常,因为我们事件就是绑定在 ul 上面的。

此时我们可以对点击的节点进行一个小小的判断,从而保证用户只在点击 li 的时候才触发事件,如下:

var colorList = document.getElementById("color-list");
colorList.addEventListener("click", function (event) {if (event.target.nodeName === 'LI') {alert('点击 li');}
})

🌟真题解答

  • 谈一谈事件委托以及冒泡原理

参考答案:

事件委托,又被称之为事件代理。在 JavaScript 中,添加到页面上的事件处理程序数量将直接关系到页面整体的运行性能。导致这一问题的原因是多方面的。

首先,每个函数都是对象,都会占用内存。内存中的对象越多,性能就越差。其次,必须事先指定所有事件处理程序而导致的 DOM 访问次数,会延迟整个页面的交互就绪时间。

对事件处理程序过多问题的解决方案就是事件委托。

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

事件冒泡(event bubbling),是指事件开始时由最具体的元素(文档中嵌套层次最深的那个节点)接收,然后逐级向上传播到较为不具体的节点(文档)。

🌟总结

本篇文章是关于JavaScript的一道面试题,后续还会持续更新HTML、CSS、JavaScript、Node.js、Vue.js、网络等前端相关面试题。如果文中出现有瑕疵的地方各位通过评论或者私信联系我,我们一起进步,有兴趣的伙伴可以关注订阅: 前端面试题大全  

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/190875.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

SmartSoftHelp8数据库连接字符串强优化,高并发配置

1.设置数据库是否异步连接 2.数据库连接是否复用 3.最大链接数 4.最小连接数 5.等待时间 6.生命周期 下载地址&#xff1a; 百度网盘 请输入提取码

24、蜂鸣器

蜂鸣器介绍 蜂鸣器是一种将电信号转换为声音信号的器件&#xff0c;常用来产生设备的按键音、报警音等提示信号 蜂鸣器按驱动方式可分为有源蜂鸣器和无源蜂鸣器 有源蜂鸣器&#xff1a;内部自带振荡源&#xff0c;将正负极接上直流电压即可持续发声&#xff0c;频率固定 无源蜂…

【linux】信号——信号保存+信号处理

信号保存信号处理 1.信号保存1.1信号其他相关概念1.2信号在内核中的表示 2.信号处理2.1信号的捕捉流程2.2sigset_t2.3信号集操作函数2.4实操2.5捕捉信号的方法 3.可重入函数4.volatile5.SIGCHLD信号 自我名言&#xff1a;只有努力&#xff0c;才能追逐梦想&#xff0c;只有努力…

计算机毕业设计 基于SpringBoot的敬老院管理系统的设计与实现 Java实战项目 附源码+文档+视频讲解

博主介绍&#xff1a;✌从事软件开发10年之余&#xff0c;专注于Java技术领域、Python人工智能及数据挖掘、小程序项目开发和Android项目开发等。CSDN、掘金、华为云、InfoQ、阿里云等平台优质作者✌ &#x1f345;文末获取源码联系&#x1f345; &#x1f447;&#x1f3fb; 精…

数据结构与算法-静态查找表

&#x1f31e; “清醒 自律 知进退&#xff01;” 查找 &#x1f388;1.查找的相关概念&#x1f388;2.静态查找表&#x1f52d;2.1静态查找表的类定义&#x1f52d;2.2顺序查找&#x1f52d;2.3二分查找&#x1f50e;二分查找例题 &#x1f52d;2.4分块查找&#x1f52d;2.5三…

理解BatchNormalization层的作用

深度学习 文章目录 深度学习前言一、“Internal Covariate Shift”问题二、BatchNorm的本质思想三、训练阶段如何做BatchNorm四、BatchNorm的推理(Inference)过程五、BatchNorm的好处六、机器学习中mini-batch和batch有什么区别 前言 Batch Normalization作为最近一年来DL的重…

logistic回归详解

为什么不直接统计标签数和预测结果数&#xff0c;计算精度&#xff1f; 因为 存在梯度为0的情况梯度不连续 为什么叫logistic回归 logistic是因为加了一个sigmoid函数&#xff0c;将输出预测值映射到【0&#xff0c;1】 有时候使用MSE损失函数&#xff0c;拟合 有时候使用c…

selenium三猛士

selenium包括三个项目&#xff0c;分别是&#xff1a;Selenium WebDriver,Selenium IDE&#xff0c;Selenium Grid。 Selenium WebDriver Selenium WebDriver是客户端API接口&#xff0c;测试人员通过调用这些接口&#xff0c;来访问浏览器驱动&#xff0c;浏览器再访问浏览器…

利用Python中的Manim进行数学绘画和创作

相信很多同学就算没听过3Blue1Brown&#xff0c;也一定曾看过他们出品的视频&#xff0c;其从独特的视觉角度解说各种数学概念&#xff0c;内容包括线性代数、微积分、神经网络、傅里叶变换以及四元数等晦涩难懂的知识点。例如最火的《线性代数本质》系列视频。 那么这些视频是…

【算法】动态规划中的路径问题

君兮_的个人主页 即使走的再远&#xff0c;也勿忘启程时的初心 C/C 游戏开发 Hello,米娜桑们&#xff0c;这里是君兮_&#xff0c;如果给算法的难度和复杂度排一个排名&#xff0c;那么动态规划算法一定名列前茅。今天&#xff0c;我们通过由简单到困难的两道题目带大家学会动…

文字、图片免费生成视频和专属数字人,你不来试试吗?

查看生成的效果&#xff1a;AI产生的视频&#xff08;关注公众号&#xff0c;获取精彩内容&#xff09; 您是否想要制作一些令人惊叹的视频&#xff0c;但又没有视频编辑的技能或经验&#xff1f;您是否想要利用人工智能的力量&#xff0c;让您的图片和声音变成动态的视频&…

如何强制任何Android应用程序进入全屏沉浸式模式(无生根)

谷歌在2012年发布了Android版本的Chrome&#xff0c;并且从未费心给它一个全屏模式。如果您厌倦了等待自己喜欢的Android应用程序提供全屏&#xff0c;则可以使用沉浸式模式自行完成。 来吧&#xff0c;谷歌&#xff0c;我真的一直在乞求你多年&#xff01;没有理由不给我们一…

【Go语言反射reflect】

Go语言反射reflect 一、引入 先看官方Doc中Rob Pike给出的关于反射的定义&#xff1a; Reflection in computing is the ability of a program to examine its own structure, particularly through types; it’s a form of metaprogramming. It’s also a great source of …

C语言——深入理解指针(4)

目录 1.回调函数 2. qsort 函数的使用 2.1 排序整型数据 2.2 排序结构体数据 3. qsort 函数的模拟实现 1.回调函数 回调函数就是通过一个函数指针调用的函数。 你把函数的地址作为参数传递给另一个函数&#xff0c;当这个指针被用来调用其所指向的函数时&#xff0c;被调…

【web安全】ssrf漏洞的原理与使用

前言 菜某对ssrf漏洞的总结。 ssrf的作用 主要作用&#xff1a;访问外界无法访问的内网进行信息收集。 1.进行端口扫描&#xff0c;资源访问 2.指纹信息识别&#xff0c;访问相应的默认文件 3.利用漏洞或者和payload进一步运行其他程序 4.get类型漏洞利用&#xff0c;传参数…

用CHAT 写一份销售人员激励方案

问CHAT &#xff1a;写一份销售人员早会激励方案 CHAT回复&#xff1a; 标题&#xff1a;鼓舞斗志&#xff0c;迎接新的一天 -- 销售人员早会激励方案 一、会议的氛围设定&#xff1a; 深呼吸&#xff0c;准备开始一天的事业&#xff1a;清晨的阳光&#xff0c;温暖而明亮&…

Nat. Rev. Chem. | 一份关于用机器学习研究化学问题的评估指导

今天为大家介绍的是来自Tiago Rodrigues团队的一篇论文。机器学习&#xff08;ML&#xff09;有望解决化学领域的重大挑战。尽管ML工作流程的适用性极广&#xff0c;但人们通常发现评估研究设计多种多样。目前评估技术和指标的异质性导致难以&#xff08;或不可能&#xff09;比…

Android BT HCI分析简介

对于蓝牙开发者来说&#xff0c;通过HCI log可以帮助我们更好地分析问题&#xff0c;理解蓝牙协议&#xff0c;就好像网络开发一定要会使用Wireshark分析网络协议一样。 本篇主要介绍HCI log的作用、如何抓取一份HCI log&#xff0c;并结合一个实际的例子来说明如何分析HCI log…

亚马逊云科技 re:Invent 2023:科技前沿风向标,探索未来云计算之窗

文章目录 一、前言二、什么是亚马逊云科技 re:Invent&#xff1f;三、亚马逊云科技 re:Invent 2023 将于何时何地举行四、亚马逊云科技 re:Invent 2023 有什么内容&#xff1f;4.1 亚马逊云科技 re:Invent 2023 主题演讲4.2 亚马逊云科技行业专家探实战 五、更多亚马逊云科技活…

单片机----汇编语言入门知识点

目录 汇编语句的格式 汇编语句的两个基本语句 子程序的调用 查表程序设计 1.x和y均为单字节数的查表程序设计 2.x为单字节数y为双字节数的查表程序设计 3.x和y均为双字节数的查表程序设计 分支转移程序设计 1.单分支选择结构 2.多分支选择结构 循环程序设计 (1) 计…