事件與事件流 用戶在點擊網頁上某一按鈕時,瀏覽器會想辦法接收這一操作,如何接收呢? 瀏覽器會為點擊操作劃定若幹個範圍,從小到大依次是按鈕本身,包含這個按鈕的元素, 最後就是整個頁面。這一操作稱為事件,而接收事件的次序稱為事件流。 事件流總共有兩種形式:事件冒泡,事件捕獲。 事件冒泡 事件冒泡就是從小 ...
事件與事件流
用戶在點擊網頁上某一按鈕時,瀏覽器會想辦法接收這一操作,如何接收呢? 瀏覽器會為點擊操作劃定若幹個範圍,從小到大依次是按鈕本身,包含這個按鈕的元素, 最後就是整個頁面。這一操作稱為事件,而接收事件的次序稱為事件流。 事件流總共有兩種形式:事件冒泡,事件捕獲。
事件冒泡
事件冒泡就是從小到大,從具體對象到不具體對象,像泡泡一樣逐級向上
<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觸發了若幹次。
總結
事件:用戶的某一操作
事件流:瀏覽器接受事件的順序
事件冒泡:從具體對象到不具體對象,逐級向上接收
事件捕獲:從不具體對象到具體對象,逐級向下接收