首页 > 编程笔记 > JavaScript笔记
JS事件冒泡
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】事件冒泡演示。
图 2:事件冒泡运行结果
由图 2 可见,虽然 div3 因为绝对定位而脱离了文档,但其所触发的事件仍然会逐级向上传递单击事件给 div2、div1、document 和 window,即便注释掉 div2 的单击事件。
在前面介绍了,addEventListener() 的第三个参数取 false 值时,将会实现事件冒泡。下面通过示例 2 演示使用 addEventListener() 实现事件冒泡。
【例 2】使用 addEventListener() 实现事件冒泡。
例 2 在 Chrome 浏览器中的运行结果如图 3 所示。由图 3 可见事件的接受顺序为 div3→div2→div1。
图 3:使用 addEventListener() 实现事件冒泡
事件冒泡在实际应用中有时会给我们带来便利,例如示例 3 的“分享”功能就是使用了事件冒泡来实现的。
【例 3】使用事件冒泡实现“分享”功能。
图 4:初始状态
当我们将鼠标光标移到 div2(“分享到”)上后,div2 的鼠标光标移入事件将会传递给它的父级元素 div1(图标列表),因而此时会触发 div1 的鼠标光标移入事件,而使 div1 显示出来,结果如图 5 所示。
图 5:鼠标光标移入“分享到”后的状态
当将鼠标光标从 div2 移开时,div2 的鼠标光标移开事件同样会传递给 div1,从而触发 div1 的鼠标光标移开事件,而使 div1 隐藏起来,即回到图 4 所示状态。
在程序开发时,事件冒泡在某些时候会带来便利,但有时却又会带来不好的影响,此时就需要阻止事件冒泡。所有标准浏览器(IE9 及其以上版本、Chrome 和 Firefox)都通过事件对象调用 stopPropagation() 来实现事件冒泡的阻止。
下面通过示例 4 来演示事件冒泡的阻止。
【例 4】事件冒泡的阻止。
图 6:单击按钮显示 div
再单击除按钮以外的其他地方则隐藏 div,如图 7 所示。
图 7:单击除按钮以外的其他地方隐藏 div
由示例 JS 代码,可知 button 和 document 两个元素都使用了事件属性来绑定单击事件处理函数,因而它们将会实现事件冒泡。因而当单击按钮时,如果不阻止 button 元素的事件冒泡,button 触发的单击事件将会传递到 document。
根据事件冒泡的事件接受顺序,可知单击按钮后将显示 div,但因为事件冒泡,document 接着也触发了单击事件,而其却是隐藏 div,这样最终的运行结果是,单击按钮后将永远都无法显示 div。可见,要实现我们所要求的功能,就必须在单击按钮后,只有 button 触发单击事件,这就需要阻止 button 的事件冒泡。
本节介绍事件冒泡,下节再介绍事件捕获。
事件冒泡:当一个元素接收到事件时,会把它接收到的事件逐级向上传播给它的祖先元素,一直传到顶层的 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。
图 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 所示;
图 6:单击按钮显示 div
再单击除按钮以外的其他地方则隐藏 div,如图 7 所示。
图 7:单击除按钮以外的其他地方隐藏 div
由示例 JS 代码,可知 button 和 document 两个元素都使用了事件属性来绑定单击事件处理函数,因而它们将会实现事件冒泡。因而当单击按钮时,如果不阻止 button 元素的事件冒泡,button 触发的单击事件将会传递到 document。
根据事件冒泡的事件接受顺序,可知单击按钮后将显示 div,但因为事件冒泡,document 接着也触发了单击事件,而其却是隐藏 div,这样最终的运行结果是,单击按钮后将永远都无法显示 div。可见,要实现我们所要求的功能,就必须在单击按钮后,只有 button 触发单击事件,这就需要阻止 button 的事件冒泡。
所有教程
- C语言入门
- C语言编译器
- C语言项目案例
- 数据结构
- C++
- STL
- C++11
- socket
- GCC
- GDB
- Makefile
- OpenCV
- Qt教程
- Unity 3D
- UE4
- 游戏引擎
- Python
- Python并发编程
- TensorFlow
- Django
- NumPy
- Linux
- Shell
- Java教程
- 设计模式
- Java Swing
- Servlet
- JSP教程
- Struts2
- Maven
- Spring
- Spring MVC
- Spring Boot
- Spring Cloud
- Hibernate
- Mybatis
- MySQL教程
- MySQL函数
- NoSQL
- Redis
- MongoDB
- HBase
- Go语言
- C#
- MATLAB
- JavaScript
- Bootstrap
- HTML
- CSS教程
- PHP
- 汇编语言
- TCP/IP
- vi命令
- Android教程
- 区块链
- Docker
- 大数据
- 云计算