javascript:深刻理解事件流

事件流

定義
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

clipboard.png

問題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

clipboard.png

結論1:當點擊橘色塊外淺藍色部分的時候,一樣的也彈出了789,而淺藍色部分是嵌套在wrap元素以內的元素,故可得出結論,當元素註冊了事件,此事件的做用範圍爲:1.元素本身所佔頁面空間部分加嵌套元素所佔空間範圍(若嵌套元素覆蓋在容器元素上,則事件的做用範圍爲容器元素自身所佔空間大小)

事件的執行順序討論

問題2:根據上面的示例1,那麼這裏你們能夠再思考一個問題,若容器元素wrap以及其嵌套元素outerinner都註冊了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事件流

DOM事件流

DOM2級事件」規定的事件流包括三個階段:事件捕獲階段==>處於目標階段==>事件冒泡階段。首先發生的是事件捕獲階段,爲截獲事件提供了機會。而後是實際的目標接收事件。最後一個階段是冒泡階段,如下圖片來自w3c

eventflow.png

示例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

相關文章
相關標籤/搜索