DOM事件流(event flow )存在三個階段:事件捕獲階段、處於目標階段、事件冒泡階段。javascript
事件捕獲(event capturing):通俗的理解就是,當鼠標點擊或者觸發dom事件時,瀏覽器會從根節點開始由外到內進行事件傳播,即點擊了子元素,若是父元素經過事件捕獲方式註冊了對應的事件的話,會先觸發父元素綁定的事件。html
事件冒泡(dubbed bubbling):與事件捕獲偏偏相反,事件冒泡順序是由內到外進行事件傳播,直到根節點。java
不管是事件捕獲仍是事件冒泡,它們都有一個共同的行爲,就是事件傳播,它就像一跟引線,只有經過引線才能將綁在引線上的鞭炮(事件監聽器)引爆,試想一下,若是引線不導火了,那鞭炮就只有一響了!!!瀏覽器
dom標準事件流的觸發的前後順序爲:先捕獲再冒泡,即當觸發dom事件時,會先進行事件捕獲,捕獲到事件源以後經過事件傳播進行事件冒泡。不一樣的瀏覽器對此有着不一樣的實現,IE10及如下不支持捕獲型事件,因此就少了一個事件捕獲階段,IE十一、Chrome 、Firefox、Safari等瀏覽器則同時存在。dom
說到事件冒泡與捕獲就不得不提一下兩個用於事件綁定的方法addEventListener、attachEvent。固然還有其它的事件綁定的方式這裏不作介紹。 函數
addEventListener(event, listener, useCapture) ui
·參數定義:event---(事件名稱,如click,不帶on),listener---事件監聽函數,useCapture---是否採用事件捕獲進行事件捕捉,spa
默認爲false,即採用事件冒泡方式code
addEventListener在 IE十一、Chrome 、Firefox、Safari等瀏覽器都獲得支持。htm
attachEvent(event,listener)
·參數定義:event---(事件名稱,如onclick,帶on),listener---事件監聽函數。
attachEvent主要用於IE瀏覽器,而且僅在IE10及如下才支持,IE11已經廢了這個方法了(微軟仍是挺識趣的,慢慢向標準靠攏)。
說了一籮筐定義,下面就用上面這兩個方法經過栗子來解釋一下事件捕獲與事件冒泡的具體表現行爲差別。
事件冒泡
慄1:
<html lang="zh-cn"> <head> <meta http-equiv="Content-Type" content="text/html; charset=utf-8"> <title>js事件機制</title> <style> #parent{ width: 200px; height:200px; text-align: center; line-height: 3; background: green; } #child{ width: 100px; height: 100px; margin: 0 auto; background: orange; } </style> </head> <body> <div id="parent"> 父元素 <div id="child"> 子元素 </div> </div> <script type="text/javascript"> var parent = document.getElementById("parent"); var child = document.getElementById("child"); document.body.addEventListener("click",function(e){ console.log("click-body"); },false); parent.addEventListener("click",function(e){ console.log("click-parent"); },false); child.addEventListener("click",function(e){ console.log("click-child"); },false); </script> </body> </html>
經過"addEventListener"方法,採用事件冒泡方式給dom元素註冊click事件,點擊子元素會發生什麼呢?若是你對事件冒泡有必定了解的話那你確定知道上面的代碼會輸出的順序,沒錯,以下圖所示:
事件觸發順序是由內到外的,這就是事件冒泡,雖然只點擊子元素,可是它的父元素也會觸發相應的事件,其實這是合理的,由於子元素在父元素裏面,點擊子元素也就至關於變相的點擊了父元素,這樣理解對吧?
這裏有同窗可能要問了,若是點擊子元素不想觸發父元素的事件怎麼辦?確定能夠的,那就是中止事件傳播---event.stopPropagation();
修改慄1的代碼,在子元素的監聽函數中加入中止事件傳播的操做,慄2
child.addEventListener("click",function(e){ console.log("click-child"); e.stopPropagation(); },false);
在點擊子元素的時候就只彈出了子元素那條信息,父元素的事件沒有觸發,由於事件已經中止傳播了,冒泡階段也就中止了。
事件冒泡差很少就講述完了,別急,捕獲還沒說呢!
事件捕獲
慄3,修改栗子1中的代碼,給parent元素註冊一個捕獲事件,以下
var parent = document.getElementById("parent"); var child = document.getElementById("child"); document.body.addEventListener("click",function(e){ console.log("click-body"); },false); parent.addEventListener("click",function(e){ console.log("click-parent---事件傳播"); },false);
//新增事件捕獲事件代碼 parent.addEventListener("click",function(e){ console.log("click-parent--事件捕獲"); },true); child.addEventListener("click",function(e){ console.log("click-child"); },false);
若是你看明白了我前面說的那些,你就知道這個栗子的輸出順序了。
父元素經過事件捕獲的方式註冊了click事件,因此在事件捕獲階段就會觸發,而後到了目標階段,即事件源,以後進行事件傳播,parent同時也用冒泡方式註冊了click事件,因此這裏會觸發冒泡事件,最後到根節點。這就是整個事件流程。
上面介紹了事件冒泡、事件捕獲、事件傳播,下面講一下若是經過以上三個知識點進行事件委託
委託在JQuery中已經獲得了實現,即經過$(selector).on(event,childSelector,data,function,map)實現委託,通常用於動態生成的元素,固然JQuery也是經過原聲的js去實現的,下面舉一個簡單的栗子,經過js實現經過parent元素給child元素註冊click事件
var parent = document.getElementById("parent"); var child = document.getElementById("child"); parent.onclick = function(e){ if(e.target.id == "child"){ console.log("您點擊了child元素") } }
雖然沒有直接只child元素註冊click事件,但是點擊child元素時卻彈出了提示信息。
到這裏是否是對js的事件機制有必定的瞭解了呢?感受有幫助的話就看看下面的小黃臉,你懂得哦!
若有錯誤,歡迎指正
若有問題,歡迎提問