事件,就是文檔或瀏覽器窗口發生的一些特定的交互瞬間。(by 《JavaScript高級程序設計》)
好比鼠標點擊,雙擊,滾動條滑動...javascript
先來看一個簡單的例子:html
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Document</title> </head> <body> <div class="main"> <div class="btn-wrap"> <button id="btn">點擊</button> </div> <div> </body> </html>
這時候咱們點擊btn
的同時,也能夠視爲同時點擊了btn
的容器元素,甚至單擊了整個頁面。
事件流指的是從頁面接收事件的順序。
關於事件流,IE和Netscape提出了差很少相反的概念,IE提出的就是廣爲人知的事件冒泡流,而Netscape提出的則是事件捕獲流。java
事件冒泡,即事件開始時由最具體的元素接收,如上面例子中的btn
,而後逐漸向上級傳播到較爲不具體的節點。DOM2級事件
規定addEventListener
方法的第三個參數設爲false
,表示事件在冒泡階段觸發。瀏覽器
注:使用頻繁的事件委託實際上也是利用了事件冒泡。spa
仍是相同的DOM結構爲例:設計
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Document</title> </head> <body> <div class="main"> <div class="btn-wrap"> <button id="btn">點擊</button> </div> <div> <script type="text/javascript"> var btn=document.querySelector("#btn"), btnWrap=document.querySelector(".btn-wrap"), main=document.querySelector(".main"), body=document.querySelector("body"), html=document.querySelector("html"); btn.addEventListener("click",function(){ console.log("你點擊了ID爲btn的button元素!"); },false); btnWrap.addEventListener("click",function(){ console.log("你點擊了class爲btn-wrap的DIV元素!"); },false); main.addEventListener("click",function(){ console.log("你點擊了class爲main的DIV元素!"); },false); body.addEventListener("click",function(){ console.log("你點擊了body元素!"); },false); html.addEventListener("click",function(){ console.log("你點擊了html元素!"); },false); document.addEventListener("click",function(){ console.log("你點擊了document對象!"); },false); </script> </body> </html>
若是咱們點擊btn
,那麼這個click事件的傳播順序以下:code
也就是,click事件首先在btn
元素上觸發,而這個元素就是咱們單擊的元素,而後click事件沿DOM樹向上傳播,在每一級的節點都會發生,直至傳播到document對象。
全部現代瀏覽器都支持事件冒泡。htm
事件捕獲,即事件從不太肯定的節點接收,而後向下傳播到最具體的節點,事件捕獲的用意在於在事件到達預期目標以前捕獲它。DOM2級事件
規定addEventListener
方法的第三個參數設爲true
,表示事件在捕獲階段觸發。
仍是相同的DOM結構爲例:
將參數改成true
對象
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Document</title> </head> <body> <div class="main"> <div class="btn-wrap"> <button id="btn">點擊</button> </div> <div> <script type="text/javascript"> var btn=document.querySelector("#btn"), btnWrap=document.querySelector(".btn-wrap"), main=document.querySelector(".main"), body=document.querySelector("body"), html=document.querySelector("html"); btn.addEventListener("click",function(){ console.log("你點擊了ID爲btn的button元素!"); },true); btnWrap.addEventListener("click",function(){ console.log("你點擊了class爲btn-wrap的DIV元素!"); },true); main.addEventListener("click",function(){ console.log("你點擊了class爲main的DIV元素!"); },true); body.addEventListener("click",function(){ console.log("你點擊了body元素!"); },true); html.addEventListener("click",function(){ console.log("你點擊了html元素!"); },true); document.addEventListener("click",function(){ console.log("你點擊了document對象!"); },true); </script> </body> </html>
若是咱們點擊btn
,那麼這個click事件的傳播順序以下:事件
在事件捕獲過程當中,document對象首先接收到click事件,而後事件沿着DOM樹依次向下傳播。
目前支持事件捕獲流的瀏覽器有:IE9,Safari,Chrome,Opera,Firefox。
因爲老版本瀏覽器不支持事件捕獲,建議你們更多的是用事件冒泡,在有特殊須要時再使用事件捕獲。
根據DOM2級事件
規定,事件流應該包括三個階段,事件捕獲階段,處於目標階段和事件冒泡階段。
仍是相同的DOM結構爲例:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Document</title> </head> <body> <div class="main"> <div class="btn-wrap"> <button id="btn">點擊</button> </div> <div> <script type="text/javascript"> var btn=document.querySelector("#btn"), btnWrap=document.querySelector(".btn-wrap"), main=document.querySelector(".main"), body=document.querySelector("body"), html=document.querySelector("html"); //冒泡 btn.addEventListener("click",function(){ console.log("你點擊了ID爲btn的button元素!"); },false); btnWrap.addEventListener("click",function(){ console.log("你點擊了class爲btn-wrap的DIV元素!"); },false); main.addEventListener("click",function(){ console.log("你點擊了class爲main的DIV元素!"); },false); body.addEventListener("click",function(){ console.log("你點擊了body元素!"); },false); html.addEventListener("click",function(){ console.log("你點擊了html元素!"); },false); document.addEventListener("click",function(){ console.log("你點擊了document對象!"); },false); //捕獲 btn.addEventListener("click",function(){ console.log("你點擊了ID爲btn的button元素!"); },true); btnWrap.addEventListener("click",function(){ console.log("你點擊了class爲btn-wrap的DIV元素!"); },true); main.addEventListener("click",function(){ console.log("你點擊了class爲main的DIV元素!"); },true); body.addEventListener("click",function(){ console.log("你點擊了body元素!"); },true); html.addEventListener("click",function(){ console.log("你點擊了html元素!"); },true); document.addEventListener("click",function(){ console.log("你點擊了document對象!"); },true); </script> </body> </html>
若是咱們點擊btn
,那麼這個click事件的傳播順序以下:
在DOM事件流中,實際的目標btn
不會接收到事件。這意味着在捕獲階段,事件從document到btn-wrap
就中止了,下一階段是「處於目標」階段,因而事件在btn
上發生,而後冒泡階段發生,事件又傳播迴文檔。
注:多數支持DOM事件流的瀏覽器都實現了一種特定行爲,即便
DOM2級事件
規範明確要求捕獲階段不會涉及目標階段,IE9,Safari,Chrome,Firefox,Opera9.5及更高版本都會在事件捕獲階段觸發事件對象上的事件,這也是上圖btn
被觸發兩次的緣由。
IE9,Safari,Chrome,Firefox,Opera都支持DOM事件流,IE8及更早版本不支持DOM事件流。
本文知識點大多來自《JavaScript高級程序設計》一書,博主在這裏也是作一次總結,鞏固一下相關知識,同時也但願沒接觸過事件流的童鞋們,有一個大概的概念。