事件与事件流
用户在点击网页上某一按钮时,浏览器会想办法接收这一操作,如何接收呢? 浏览器会为点击操作划定若干个范围,从小到大依次是按钮本身,包含这个按钮的元素, 最后就是整个页面。这一操作称为事件,而接收事件的次序称为事件流。 事件流总共有两种形式:事件冒泡,事件捕获。
事件冒泡
事件冒泡就是从小到大,从具体对象到不具体对象,像泡泡一样逐级向上
<html></html> <body> <div id="div1"> <div id="div2"> <button>click me!</button> </div> </div> </body>
当用户打开上述代码编写的页面,点击按钮时,如果浏览器采取的是事件冒泡的事件接收机制, 那么浏览器就先从button元素开始接收,然后是然后是div2,然后是div1,最终到document对象(规范是到document为止, 但是大多数浏览器都会一直冒泡到window对象),如图所示。
事件捕获
事件捕获就是事件冒泡的反序。从大到小,从不具体对象到具体对象,逐级向下。
如果浏览器采取的是事件捕获的事件接收机制, 浏览器先从document对象(规范定的是document对象,大多数浏览器是从window对象处开始接收)开始接收, 然后是<html>元素,然后是<body>元素,最后在<button>元素处接收。
<!DOCTYPE html> <html> <head> <meta charset="UTF-8" /> <meta http-equiv="contentType" content="text/html" /> <title>Test</title> </head> <body> <div id="div1"> <div id="div2"> <button>click me!</button> </div> </div> <script src="scripts/test.js" type="text/javascript"></script> </body> </html>
var div1 = document.querySelector("#div1"); var div2 = document.querySelector("#div2"); var button = document.querySelector("button"); div1.addEventListener("click",function(event){ console.log("div1"); },false); //传入false,事件冒泡 div2.addEventListener("click",function(event){ console.log("div2"); },false); button.addEventListener("click",function(event){ console.log("button"); },false);
上述代码使用addEventListener()方法,分别为div1,div2,button元素添加了事件处理程序, 并显示的指定事件流为事件冒泡机制,浏览器按具体对象到不具体对象的顺序接收事件。所以控制台输出
同一段代码,但显示的指定事件流为事件捕获机制,浏览器按不具体对象到具体对象的顺序接收事件, 控制台输出。
有什么用
理解事件流的这两种机制有什么用?其实这对理解某些DOM事件是很有好处的,比如mouseover、mouseout、mouseleave、mouseenter。 其中,mouseover和mouseout是一对儿,鼠标进入目标元素时接收mouseover,离开目标元素时接收mouseout事件。 mouseenter和mouseleave是一对儿,鼠标进入目标元素时接收mouseenter,离开目标元素时接收mouseleave事件, 但是他俩不冒泡!所以鼠标进入、离开其后代元素时,其父元素无法接受到mouseenter和mouseleave事件。
<div id="target"> <p> Lorem Ipsum is simply dummy text of the printing and typesetting industry.<br/> Lorem Ipsum has been the industry's standard dummy text ever since the 1500. </p> <p> Lorem Ipsum is simply dummy text of the printing and typesetting industry.<br/> Lorem Ipsum has been the industry's standard dummy text ever since the 1500. </p> <p> Lorem Ipsum is simply dummy text of the printing and typesetting industry.<br/> Lorem Ipsum has been the industry's standard dummy text ever since the 1500. </p> <p> Lorem Ipsum is simply dummy text of the printing and typesetting industry.<br/> Lorem Ipsum has been the industry's standard dummy text ever since the 1500. </p> </div>
var target = document.querySelector("#target"); /** * 使用mouseenter和mouseleave事件,进入target时浏览器接受mouseenter事件, * 离开target时浏览器接受mouseleave事件。 * 在target中移动鼠标(在各个<p>元素之间切换),因为不冒泡,所以target不会继续接收到mouseenter和mouseleave, * 也就不会调用相应的事件处理程序 */ target.addEventListener("mouseenter",function(event) { console.log("parent mouseenter"); },false); target.addEventListener("mouseleave",function(event) { console.log("parent mouseleave"); },false);
/**
* 使用mouseout和mouseover事件, 在target中移动鼠标(在各个<p>元素之间切换),由于事件流是事件冒泡机制,
* 所以target就会接收到其子元素冒泡而来的mouseenter和mouseleave,从而调用相应的事件处理机制
*/
target.addEventListener("mouseout",function(event) {
console.log("parent mouseout");
},false);
target.addEventListener("mouseover",function(event) {
console.log("parent mouseover");
},false);
如控制带输出所示,鼠标横穿target,mouseenter仅触发了一次,mouseleave也仅触发了一次。而mouseout、mouseover触发了若干次。
总结
事件:用户的某一操作
事件流:浏览器接受事件的顺序
事件冒泡:从具体对象到不具体对象,逐级向上接收
事件捕获:从不具体对象到具体对象,逐级向下接收
参考资料
1.《javascript高级程序设计》