当前位置: 首页 > Web前端 > CSS

你真的了解事件冒泡和事件捕获吗?

时间:2023-03-30 19:08:13 CSS

最近在复习前端的基础知识。看到事件部分的时候,刚好在笔记中发现了一段特别有趣,非常有趣的代码。按照这样的题目,基本可以消除事件冒泡和事件捕获的盲点。扫一扫。本文将带你看一看这段有趣的代码。但是,首先,我们还是要常规地过一遍一些基本的概念。事实上,它不需要太长时间。什么是事件?JavaScript和HTML之间的交互是通过事件来实现的。事件是发生在文档或浏览器窗口中的特定交互时刻。您可以使用侦听器(或事件处理程序)来订阅事件,以便在事件发生时执行适当的代码。通俗地说,这个模型其实就是一个观察者模型。(事件是对象主题,每个监听器是每个观察者)事件流事件流描述了从页面接收事件的顺序。但是IE和Netscape提出了完全相反的事件流概念。IE事件流是事件冒泡,Netscape事件流是事件捕获。打个比方,如果你把手指放在一个圆(多个同心圆)的圆心上,那么你的手指指向的不是一个圆,而是纸上所有的圆。如果你点击一个按钮,当你点击这个按钮的时候,你同时也点击了这个按钮的容器元素,甚至是整个页面。事件冒泡IE的事件流称为事件冒泡。也就是说,事件最初由最具体的元素(文档中嵌套最深的节点)接收,然后通过级别向上传播到不太具体的节点(文档)。所有现代浏览器都支持事件冒泡,并将事件一直冒泡到window对象。事件捕获事件捕获背后的想法是,不太具体的节点应该更早接收事件,而最具体的节点应该最后接收事件。事件捕获的目的是在事件到达预定目的地之前捕获事件。IE9+、Safari、Chrome、Opera和Firefox支持,并从窗口捕获(尽管DOM2级事件规范需要来自文档)。很少有人使用事件捕获,因为旧的浏览器不支持它。DOM事件流“DOM2级事件”规定事件流包括三个阶段,事件捕获阶段、目标阶段和事件冒泡阶段。事件捕获首先发生,提供了拦截事件的机会。然后实际目标接收事件。最后一个阶段是冒泡阶段,可以响应事件。上面这段话是我们DOM事件流的基础。这段非常重要。看似简单,其实包含了很多小细节。我将在以下示例中讨论这一切。一个很有趣的例子下面开始讲解这个有趣的例子,先贴代码,总体结构很简单。由于segmentfault代码过长会出现滚动条,这里我将其拆分,省略了一些不需要的节点,方便查看。

#a{宽度:300px;高度:300px;背景:粉色;}#b{宽度:200px;高度:200px;背景:蓝色;}#c{宽度:100px;高度:100px;背景:黄色;}vara=document.getElementById("a"),b=document.getElementById("b"),c=document.getElementById("c");c.addEventListener("click",function(event){console.log("c1");//注意不传第三个参数infalse,因为默认传入false//,代表冒泡阶段调用,个人认为会在target阶段调用});c.addEventListener("click",function(event){console.log("c2");},true);b.addEventListener("click",function(event){console.log("b");},true);a.addEventListener("click",function(event){console.log("a1");},true);a.addEventListener("click",function(event){console.log("a2")});a.addEventListener("click",function(event){console.log("a3");event.stopImmediatePropagation();},true);a.addEventListener("click",function(event){console.log("a4");},true);整个html页面就是下面三个小框,那么现在有三个问题:如果点击c或者b,输出是什么?(答案是a1,a3)stopImmediatePropagation包含了stopPropagation的功能,阻止了事件传播(捕获或冒泡),同时也阻止了后面绑定在元素上的事件处理器被调用,所以a4没有输出。因为拦截了事件捕获,b、c上的事件自然不会触发,所以b、c1、c2不会输出,更不会冒泡,所以a2不会输出。如果单击a,输出是什么?(答案是a1,a2,a3)不应该是a1,a3,a2吗?有的同学会说:“a1和a3是handler,在捕获阶段调用,a2在冒泡阶段调用”。True,false,但是现在事件流处于目标阶段,不是冒泡阶段,也不是捕获阶段,调用事件处理器的顺序就是注册的顺序。无论您指定true还是false。也就是说,现在点击的是盒子a本身,处于事件流的目标状态,既不是冒泡也不是捕获。(需要注意的是,此时的eventPhase为2,表示事件流处于目标阶段,当点击a时,先从文档中抓取,然后逐步寻找元素时a找到了,target和currentTarget是一致的,所以判断是结束了,不需要捕获了,这时候会按顺序执行预定的事件处理函数,然后继续执行后冒泡...)如果event.stopImmediatePropagation被注释掉,点击c,会输出什么?(答案是a1,a3,a4,b,c1,c2,a2)如果同一个事件处理器(指针相同,比如用handler保存的事件处理器),用addEventListener或者attachEvent绑定多次,如果third如果参数相同,则只调用一次。当然,如果第三个参数其中一个设置为true,另一个设置为false,就会被调用两次。这里给监听函数的回调赋了一个匿名函数,所以实际上每一个处理函数都会被调用。需要注意的是,如果你还不明白为什么在c上先触发c1,再触发c2,那么你需要看第二个问题描述的内容。以上就是本文的内容。文章最后一个例子是在网上某处看到的,具体出处忘记了。如果有人找到来源,请告诉我。参考资料:《JavaScript高级程序设计》