事件冒泡,这一逻辑学名词对于很多初次学习JavaScript的程序员还是比较抽象,我想尝试用一种直观的方式,在这里将这个东西讲透。
首先我们去查看了事件冒泡的百度解释:
当事件发生后,这个事件就要开始传播(从里到外或者从外向里)。为什么要传播呢?因为事件源本身(可能)并没有处理事件的能力,即处理事件的函数(方法)并未绑定在该事件源上。例如我们点击一个按钮时,就会产生一个click事件,但这个按钮本身可能不能处理这个事件,事件必须从这个按钮传播出去,从而到达能够处理这个事件的代码中(例如我们给按钮的onclick属性赋一个函数的名字,就是让这个函数去处理该按钮的click事件),或者按钮的父级绑定有事件函数,当该点击事件发生在按钮上,按钮本身并无处理事件函数,则传播到父级去处理。
这一解释相对比较友好,但是难免还有些官方话。
到底该怎么理解呢?我们往下看:
我写一个简单框架:
<!-- 从父元素到子元素 --> <body> <!-- 第一层 --> <div id="div1"> <!-- 第二层 --> <div id="div2"> <!-- 第三层 --> <div id="div3"> <!-- 第四层 --> <p> <!-- 第五层 --> <span> <!-- 第六层 --> 事件冒泡 </span> </p> </div> </div> </div> </body>
接下来再为此框架设置简单的样式,样式呈现:然后我们给每一个元素设置点击事件:
$(document).ready(function(){ $("body").click(function(){ alert("从外向内第一层"); }); $("#div1").click(function(){ alert("从外向内第二层"); }); $("#div2").click(function(){ alert("从外向内第三层"); }); $("#div3").click(function(){ alert("从外向内第四层"); }); $("p").click(function(){ alert("从外向内第五层"); }); $("span").click(function(){ alert("从外向内第六层"); }); });
然后我们点击每个颜色不一样的元素,得到以下结果:
(青色)点击最外层body:出现弹出框‘从外向内第一层’
(绿色)点击div1:出现弹出框‘从外向内第二层’——‘从外向内第一层’
(黄色)点击div2:出现弹出框‘从外向内第三层’——‘从外向内第二层’——‘从外向内第一层’
(红色)点击div3:出现弹出框‘从外向内第四层’——‘从外向内第三层’——‘从外向内第二层’——‘从外向内第一层’
(蓝色)点击p标签:出现弹出框‘从外向内第五层’——‘从外向内第四层’——‘从外向内第三层’——‘从外向内第二层’——‘从外向内第一层’
(棕色)点击最内层span:出现弹出框‘从外向内第六层’——‘从外向内第五层’——‘从外向内第四层’——‘从外向内第三层’——‘从外向内第二层’——‘从外向内第一层’
程序员,这有什么规律,又说明什么?
你发现了,事件是由内向外触发的。正如事件冒泡名字本身一样形象,泡泡都是从水里开始出现,向水面移动,直到溢出水面爆炸,冒泡结束。
在编程语言里,程序也可以以这样的方式去执行。我们把这样由内向外触发事件的行为叫做事件冒泡。
一个理论的产生必定是要解决某些问题,否则,理论本身就没有意义了。那么,问题来了,这东西有什么用?
1.事件冒泡可以实现多个操作的集中处理,我们可以把事件添加到一个父级元素上,避免把同样的事件添加到多个子级元素上,它可以让你在对象层的不同级别捕获事件。
2.可让不同的元素执行同一个事件,并调用这个函数,按程序执行。
打个比方:你把自己想象成领导,你手底下有一群组员。你发命令,他们执行。
值得一提的是:
并非所有事件都可以冒泡,以下事件不会冒泡:blur、focus、load、unload。
事件冒泡是从里向外。还有从外到里的捕获事件。以及DOM事件流,先从外到里,再从里到外。(今天只研究事件冒泡,关于事件捕获,后续关注我博客。)
有了事件冒泡固然很好,但是如果我只想让冒泡事件出现一次,后面不想让它再冒泡,怎么办?
JavaScript考虑到了这一点,所以又出了一种阻止事件冒泡的方法,非常好用。
我发现了一种对初学js的程序员比较友好的描述:
通常情况下我们都是一步到位,明确自己的事件触发源,并不希望浏览器自作聪明、漫无目的地去帮我们找合适的事件处理程序,即我们明确最精准目标,这种情况下我们不需要事件冒泡。另外通过对事件冒泡的理解,我们知道程序就像机器人,只要你不发号指令让它停下来,它就会一直重复执行,达不到我们想要的效果之外,这必然也增大了程序运行负担(这也牵扯到优化问题)。还有一个重要的问题是:事件冒泡处理可能会激活我们本来不想激活的事件,导致程序错乱,甚至无从下手调试,这常成为对事件冒泡原理不熟悉的程序员的棘手问题。所以必要时,我们一定要阻止事件冒泡。
一般地,阻止事件冒泡有这几种方法:
1.event.stopPropagation();
事件处理过程中,阻止了事件冒泡,但不会阻止默认行为
2.return false;
事件处理过程中,阻止了事件冒泡,也阻止了默认行为
3.event.preventDefault();
事件处理过程中,不阻止事件冒泡,但阻止默认行为
好了,在这我将完整代码上传,自己稍稍一研究,必定能搞明白时间冒泡是怎么回事。
关注我,后续更精彩!!!
<!DOCTYPE html> <html lang="zh"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <script type="text/JavaScript" src="./js/jquery-3.4.1.js"></script> <title>Document</title> <style> body{ width: 500px; height: 500px; margin: 15vh 30vw; background-color: aqua; border: black solid 2px; } #div1{ width: 400px; height: 400px; background-color: lawngreen; } #div2{ width: 300px; height: 300px; background-color: yellow; } #div3{ width: 200px; height: 200px; background-color: red; } p{ width: 100px; height: 100px; background-color: blue; } span{ background-color: brown; color: white; } </style> <script type="text/javascript"> $(document).ready(function(){ $("body").click(function(){ alert("从外向内第一层"); }); $("#div1").click(function(){ alert("从外向内第二层"); }); $("#div2").click(function(){ alert("从外向内第三层"); }); $("#div3").click(function(){ alert("从外向内第四层"); }); $("p").click(function(){ alert("从外向内第五层"); }); $("span").click(function(){ alert("从外向内第六层"); }); }); </script> </head> <!-- 从父元素到子元素 --> <body> <!-- 第一层 --> <div id="div1"> <!-- 第二层 --> <div id="div2"> <!-- 第三层 --> <div id="div3"> <!-- 第四层 --> <p> <!-- 第五层 --> <span> <!-- 第六层 --> 事件冒泡 </span> </p> </div> </div> </div> </body> </html>