2025年3月17日 星期一 甲辰(龙)年 月十六 设为首页 加入收藏
rss
您当前的位置:首页 > 计算机 > 编程开发 > JavaScript

JS事件冒泡

时间:03-07来源:作者:点击数:78

JavaScript 事件流描述的是从页面中接受事件的顺序。IE 和 Netscape 开发团队提出了两个截然相反的事件流概念,IE 的事件流是事件冒泡(event bubbling),Netscape 的事件流是事件捕获(event capturing)。

本节介绍事件冒泡,下节再介绍事件捕获。

事件冒泡:当一个元素接收到事件时,会把它接收到的事件逐级向上传播给它的祖先元素,一直传到顶层的 window 对象(关于最后传播到的顶层对象,不同浏览器有可能不同,例如 IE9 及其以上的 IE、FireFox、Chrome、Safari 等浏览器,事件冒泡的顶层对象为 window 对象,而 IE7/8 顶层对象则为 document对象)。

例如,在 Chrome 浏览器中,当用户单击了<div>元素,click 事件将按照 <div>→<body>→<html>→document→window 的顺序进行传播,如图 1 所示。事件冒泡可以形象地比喻为把一块石头投入水中,泡泡会一直从水底冒出水面,也就是说从下向上开始传播。

事件冒泡时事件的传播顺序
图 1:事件冒泡时事件的传播顺序

事件冒泡对所有浏览器都是默认存在的,且由元素的 HTML 结构决定,而不是由元素在页面中的位置决定,所以即便使用定位或浮动使元素脱离父元素的范围,单击元素时,其依然存在冒泡现象。

使用 addEventListener() 绑定事件,当第三个参数为 false 时,事件为冒泡;为 true 时,事件为捕获。而使用事件源对象的事件属性绑定事件函数以及使用 HTML 标签事件属性绑定事件函数的事件流都是事件冒泡。

【例 1】事件冒泡演示。

  • <!doctype html>
  • <html>
  • <head>
  • <meta charset="utf-8">
  • <title>事件冒泡演示</title>
  • <style>
  • div{padding:30px;}
  • #div1{background:red;}
  • #div2{background:green;}
  • #div3{background:blue;position:absolute;top:200px;}
  • </style>
  • <script>
  • window.onload = function(){
  • //获取各个元素
  • var oBody = document.getElementById('body1');
  • var oDiv1 = document.getElementById('div1');
  • var oDiv2 = document.getElementById('div2');
  • var oDiv3 = document.getElementById('div3');
  • //对各个元素的单击事件绑定事件处理函数fn1
  • window.onclick = fn1;
  • document.onclick = fn1;
  • oBody.onclick = fn1;
  • oDiv1.onclick = fn1;
  • //oDiv2.onclick = fn1;
  • oDiv3.onclick = fn1
  • function fn1(){//定义事件处理函数
  • console.log(this);
  • }
  • };
  • </script>
  • </head>
  • <body id="body1">
  • <div id="div1">
  • <div id="div2">
  • <div id="div3"></div>
  • </div>
  • </div>
  • </body>
  • </html>

例 1 对获取到的各个元素都使用事件属性绑定事件处理函数,因而这些元素都会实现事件冒泡。当单击 div3 时,div3 作为事件冒泡的最低层元素,会首先触发单击事件,在 Chrome 浏览器中的运行结果如图 2 所示。

事件冒泡运行结果
图 2:事件冒泡运行结果

由图 2 可见,虽然 div3 因为绝对定位而脱离了文档,但其所触发的事件仍然会逐级向上传递单击事件给 div2、div1、document 和 window,即便注释掉 div2 的单击事件。

在前面介绍了,addEventListener() 的第三个参数取 false 值时,将会实现事件冒泡。下面通过示例 2 演示使用 addEventListener() 实现事件冒泡。

【例 2】使用 addEventListener() 实现事件冒泡。

  • <!doctype html>
  • <html>
  • <head>
  • <meta charset="utf-8">
  • <title>使用addEventListener()实现事件冒泡</title>
  • <style>
  • div{padding:30px;}
  • #div1{background:red;}
  • #div2{background:green;}
  • #div3{background:blue;position:absolute;top:200px;}
  • </style>
  • <script>
  • window.onload = function(){
  • var oDiv1 = document.getElementById('div1');
  • var oDiv2 = document.getElementById('div2');
  • var oDiv3 = document.getElementById('div3');
  • //调用addEventListener()实现事件冒泡
  • oDiv1.addEventListener('click',fn1,false);
  • oDiv2.addEventListener('click',fn1,false);
  • oDiv3.addEventListener('click',fn1,false);
  • function fn1(){
  • console.log(this);
  • }
  • };
  • </script>
  • </head>
  • <body id="body1">
  • <div id="div1">
  • <div id="div2">
  • <div id="div3"></div>
  • </div>
  • </div>
  • </body>
  • </html>

例 2 中 div1、div2 和 div3 元素均使用第三个参数为 false 的 addEventListener() 绑定事件函数,因而这 3 个元素将实现事件冒泡。在 Chrome 浏览器中运行后,当单击 div3 时,div3 作为事件冒泡的最低层元素,会首先触发单击事件,然后 div3 逐级向上传递单击事件给 div2 和 div1。

例 2 在 Chrome 浏览器中的运行结果如图 3 所示。由图 3 可见事件的接受顺序为 div3→div2→div1。

使用 addEventListener() 实现事件冒泡
图 3:使用 addEventListener() 实现事件冒泡

事件冒泡在实际应用中有时会给我们带来便利,例如示例 3 的“分享”功能就是使用了事件冒泡来实现的。

【例 3】使用事件冒泡实现“分享”功能。

  • <!doctype html>
  • <html>
  • <head>
  • <meta charset="utf-8">
  • <title>使用事件冒泡实现"分享"功能</title>
  • <style>
  • #div1{width:80px;height:150px;border:black 1px solid;position:absolute;
  • left:-82px;top:100px;}
  • #div2{width:30px;height:70px;position:absolute;right:-30px;top:45px;
  • background:black;color:white;text-align:center;}
  • ul{list-style:none;padding:0 20px;}
  • img{width:36px;height:39px;}
  • </style>
  • <script>
  • window.onload = function(){
  • var oDiv = document.getElementById('div1');
  • oDiv.onmouseover = function(){//鼠标光标移入,使div1显示
  • this.style.left = '0px';
  • }
  • oDiv.onmouseout = function(){//鼠标光标移出,使div1隐藏
  • this.style.left = '-82px';
  • }
  • };
  • </script>
  • </head>
  • <body>
  • <div id="div1">
  • <ul>
  • <a href="#"><li><img src="images/qq.png"/></li></a>
  • <a href="#"><li><img src="images/sina.png"/></li></a>
  • <a href="#"><li><img src="images/renren.png"/></li></a>
  • </ul>
  • <div id="div2">分享到</div>
  • </div>
  • </body>
  • </html>

例 3 在 Chrome 浏览器中运行后的初始状态如图 4 所示。

初始状态
图 4:初始状态

当我们将鼠标光标移到 div2(“分享到”)上后,div2 的鼠标光标移入事件将会传递给它的父级元素 div1(图标列表),因而此时会触发 div1 的鼠标光标移入事件,而使 div1 显示出来,结果如图 5 所示。

鼠标光标移入“分享到”后的状态
图 5:鼠标光标移入“分享到”后的状态

当将鼠标光标从 div2 移开时,div2 的鼠标光标移开事件同样会传递给 div1,从而触发 div1 的鼠标光标移开事件,而使 div1 隐藏起来,即回到图 4 所示状态。

在程序开发时,事件冒泡在某些时候会带来便利,但有时却又会带来不好的影响,此时就需要阻止事件冒泡。所有标准浏览器(IE9 及其以上版本、Chrome 和 Firefox)都通过事件对象调用 stopPropagation() 来实现事件冒泡的阻止。

注:IE7/8 等非标准的 IE 只能使用设置事件对象的 cancelBubble 属性值为 true 的方法来阻止事件冒泡。

阻止事件冒泡的方法格式如下:

事件对象.stopPropagation();//针对标准浏览器

下面通过示例 4 来演示事件冒泡的阻止。

【例 4】事件冒泡的阻止。

  • <!doctype html>
  • <html>
  • <head>
  • <meta charset="utf-8">
  • <title>阻止事件冒泡</title>
  • <style>
  • #div1{width:100px;height:200px;border:1px solid red;display:none;}
  • </style>
  • <script>
  • window.onload = function(){
  • var oBtn = document.getElementById('btn');
  • var oDiv = document.getElementById('div1');
  • oBtn.onclick = function(ev){
  • //阻止事件冒泡的兼容处理:
  • ev.stopPropagation();
  • oDiv.style.display = 'block';//显示div
  • };
  • document.onclick = function(){
  • oDiv.style.display = 'none';//隐藏div
  • }
  • };
  • </script>
  • </head>
  • <body>
  • <div id="div1"></div>
  • <input type="button" id="btn" value="显示DIV"/>
  • </body>
  • </html>

例 4 的作用是单击按钮时,显示 div,如图 6 所示;

单击按钮显示div
图 6:单击按钮显示 div

再单击除按钮以外的其他地方则隐藏 div,如图 7 所示。

单击除按钮以外的其他地方隐藏div
图 7:单击除按钮以外的其他地方隐藏 div

由示例 JS 代码,可知 button 和 document 两个元素都使用了事件属性来绑定单击事件处理函数,因而它们将会实现事件冒泡。因而当单击按钮时,如果不阻止 button 元素的事件冒泡,button 触发的单击事件将会传递到 document。

根据事件冒泡的事件接受顺序,可知单击按钮后将显示 div,但因为事件冒泡,document 接着也触发了单击事件,而其却是隐藏 div,这样最终的运行结果是,单击按钮后将永远都无法显示 div。可见,要实现我们所要求的功能,就必须在单击按钮后,只有 button 触发单击事件,这就需要阻止 button 的事件冒泡。

方便获取更多学习、工作、生活信息请关注本站微信公众号城东书院 微信服务号城东书院 微信订阅号
上一篇:W3C标准事件流 下一篇:JS事件捕获
推荐内容
相关内容
栏目更新
栏目热门