定義:
1.事件流
描述的是從頁面中接收事件的順序,也可理解爲事件在頁面中傳播的順序。
2.事件
就是用戶或瀏覽器自身執行的某種動做。諸如click(點擊)、load(加載)、mouseover(鼠標懸停)。
3.事件處理程序
響應某個事件的函數就叫事件處理程序(或事件偵聽器)。css
下面所示例子註冊事件的方式均使用DOM2級事件定義的事件處理程序進行註冊,兼容性的問題不涉及。'DOM2級事件'定義了兩個方法,用於處理指定和刪除事件處理程序的操做:addEventListener()
和removeEventListener()
。全部DOM節點中都包含這兩個方法,而且它們都接收3個參數:要處理的事件名、做爲事件處理程序的函數和一個布爾值。當這個布爾值爲true
時,表示在捕獲階段調用事件處理程序;若果是false
,表示在冒泡階段調用事件處理程序。html
示例1瀏覽器
html函數
<div id="wrap"> <div id="outer"> <div id="inner"></div> </div> </div>
cssspa
#wrap { width: 200px; height: 200px; background: orange; } #outer { position: relative; top: 50px; left: 50px; width: 100px; height: 100px; background: #eeddff; } #inner { position: relative; top: 25px; left:25px; width: 50px; height: 50px; background: #44ddff; }
js3d
var wrap = document.getElementById('wrap'); wrap.addEventListener('click',function(){ alert('789'); },false);
outputcode
問題1:容器元素wrap註冊了事件,那麼此事件的做用範圍是什麼?htm
思考1:根據上面例子,當點擊橘色塊中(包括被子元素覆蓋的部分)任何一部分時,都會彈出789,點擊橘色塊外面的部分並無任何反應,那麼咱們是否是就能夠得出這這樣結論,元素註冊事件的做用範圍爲元素自身在頁面中所佔的空間大小,可是真的就是這樣嗎?下面咱們作個試驗blog
試驗1:
css代碼修改以下,其餘部分同上seo
#wrap { width: 200px; height: 200px; background: orange; } #outer { position: relative; top: 50px; left: 50px; width: 100px; height: 100px; background: #eeddff; } /*inner中的top被修改*/ #inner { position: relative; top: 152px; left:25px; width: 50px; height: 50px; background: #44ddff; }
output
結論1:當點擊橘色塊外淺藍色部分的時候,一樣的也彈出了789,而淺藍色部分是嵌套在wrap元素以內的元素,故可得出結論,當元素註冊了事件,此事件的做用範圍爲:1.元素本身所佔頁面空間部分加嵌套元素所佔空間範圍(若嵌套元素覆蓋在容器元素上,則事件的做用範圍爲容器元素自身所佔空間大小)
問題2:根據上面的示例1
,那麼這裏你們能夠再思考一個問題,若容器元素wrap
以及其嵌套元素outer
,inner
都註冊了click事件,根據試驗1
得出的結論,那麼嵌套在最裏層的元素inner
所佔頁面的空間範圍內,一共有3個click事件都做用在其上,那麼當在inner元素的做用範圍內點擊頁面時,3個事件的事件處理程序執行的順序又是如何的?
要解決上面我提出的問題2,這就涉及到了兩種處理事件流的不一樣的機制,事件冒泡和事件捕獲
IE的事件流叫事件冒泡,即事件開始時由最具體的元素(文檔中嵌套層次最深的節點)接收,而後逐級向上傳播到較爲不具體的節點。
示例2
將參數設爲false,讓元素在冒泡階段調用事件處理程序
css,html代碼同示例1
js
var wrap = document.getElementById('wrap'); var outer = document.getElementById('outer'); var inner = document.getElementById('inner'); wrap.addEventListener('click',function(){ alert('789'); },false); outer.addEventListener('click',function(){ alert('456'); },false); inner.addEventListener('click',function(){ alert('123'); },false);
結論2:在冒泡階段調用事件處理程序,上面問題的結果是這樣的:當點擊頁面中心淺藍色的部分時,先是彈出123,接着彈出456,最後彈出789。所以當容器元素及其嵌套元素都在冒泡階段
調用事件處理程序時:事件按事件冒泡的順序執行事件處理程序。
Netscape團隊提出的另外一種事件流叫事件捕獲,事件捕獲的思想是不太具體的節點應該更早接收到事件,而最具體的節點應該最後接收到事件。
示例3
將參數設爲true,讓元素在捕獲階段調用事件處理程序
css,html代碼同示例1
js
var wrap = document.getElementById('wrap'); var outer = document.getElementById('outer'); var inner = document.getElementById('inner'); wrap.addEventListener('click',function(){ alert('wrap'); },true); outer.addEventListener('click',function(){ alert('outer'); },true); inner.addEventListener('click',function(){ alert('inner'); },true);
結論3:在捕獲階段調用事件處理程序,上面問題的結果是這樣的:當點擊頁面中心淺藍色的部分時,先是彈出wrap,接着彈出outer,最後彈出inner。所以當容器元素及其嵌套元素都在捕獲階段
調用事件處理程序時:事件按事件捕獲的順序執行事件處理程序。
問題3:根據思考1,思考2得出的結果,接着又有一個問題我認爲須要思考,當同一個元素即在冒泡階段註冊了事件,又在捕獲階段註冊了同一事件,那麼當事件被觸發時,事件的執行順序又會是如何的?
要解決上面我提出的問題3,這就涉及到了DOM事件流
「DOM2級事件」規定的事件流包括三個階段:事件捕獲階段==>處於目標階段==>事件冒泡階段。首先發生的是事件捕獲階段,爲截獲事件提供了機會。而後是實際的目標接收事件。最後一個階段是冒泡階段,如下圖片來自w3c
示例4
css,html代碼同示例1
js
var wrap = document.getElementById('wrap'); var outet = document.getElementById('outer'); var inner = document.getElementById('inner'); wrap.addEventListener('click',function(){ alert('789'); },false); outer.addEventListener('click',function(){ alert('456'); },false); inner.addEventListener('click',function(){ alert('123'); },false); wrap.addEventListener('click',function(){ alert('wrap'); },true); outer.addEventListener('click',function(){ alert('outer'); },true); inner.addEventListener('click',function(){ alert('inner'); },true);
結論4:當點擊頁面中心淺藍色部分的時候,先從最不具體的節點捕獲事件,先彈出wrap,接着彈出outer。接着處於目標階段,先彈出123,再彈出inner。緊接着,事件處於冒泡階段,先彈出456,再彈出789。所以咱們能夠得出結論,當容器元素及嵌套元素,即在捕獲階段
又在冒泡階段
調用事件處理程序時:事件按DOM事件流的順序執行事件處理程序,且當事件處於目標階段時,事件調用順序決定於綁定事件的書寫順序,按上面的例子爲,先調用冒泡階段的事件處理程序,再調用捕獲階段的事件處理程序。具體demo可看評論,@ Levon