1. 程式人生 > >Javascript——淺談 Event Flow

Javascript——淺談 Event Flow

1、Javascript Events : Event Bubbling(事件冒泡)

如果事件從最特定的元素開始,則事件流中的一個階段稱為事件冒泡(DOM中可能最深的節點)然後向上流向最不特定的節點(i.e 電子文件)

當元素<div>被單擊時,單擊事件按以下順序發生(參見上圖):

  1. <div>
  2. <body>
  3. <html>
  4. Document

事件單擊首先在元素(元素單擊)上啟動。然後它向上移動DOM樹,沿著它的路徑向每個節點開火,直到它到達文件物件。


 

2、Javascript Events : Event Capturing(事件捕獲)

 

另一種事件流模型稱為事件捕獲,它首先由Netscape瀏覽器引入。

根據該模型,最不特定的節點首先接收事件,最特定的節點最後接收事件。

它的設計目的是在事件到達目標之前攔截它

參考前面的示例,單擊元素按以下順序觸發單擊事件。

  1. Document
  2. <body>
  3. <html>
  4. <div>

事件捕獲在現代瀏覽器中缺乏瀏覽器支援,因此使用者必須在特殊情況下使用事件捕獲時自由使用冒泡。


3、Javascript Events : DOM Event Flow(DOM 事件流)

DOM Level 2事件指定的事件流模型有三個階段:

  • Event Capturing Phase
  • At the target
  • Event Bubbling Phase.

首先發生事件捕獲,前提是存在攔截事件的機會。

然後實際目標獲取事件。

然後進入冒泡的最後階段,允許對事件做出最終響應。

參考前面的示例,單擊元素按上面圖中指定的順序觸發事件。


4、Javascript Events : The Capturing Phase(捕獲階段)

DOM Level 2事件定義的事件流有三個階段:捕獲階段、目標階段和事件冒泡階段。

首先是事件捕獲,它提供了一個在必要時攔截事件的機會。

然後實際目標接收事件。

最後一個階段是冒泡,允許對事件進行響應。

示例:用於事件處理的Javascript DOM。

注意:使用throwIt()函式來代替多重if語句。


5、JS事件流原理圖/process(過程)如下:

從圖中我們可以知道:

1、一個完整的JS事件流是從window開始,最後回到window的一個過程。

2、事件流被分為三個階段(1~5)捕獲過程、(5~6)目標過程、(6~10)冒泡過程。

3、在冒泡過程中6比7早觸發,也就解釋了上面那題,為什麼btn1,會比content先觸發。

然而在有些情況下JS的事件流不會根據上圖這個從捕獲過程到目標過程到冒泡過程這樣去推進的。

從表中我們可以知道在DOM Level 0事件的時候是不支援捕獲事件的。


 

6、事件的屬性及方法

  • bubbles: 布林值,表示事件是否冒泡
  • cancelable: 布林值,表示是否可以取消事件的預設行為
  • currentTarget: 元素,事件處理程式當前正在處理事件的那個元素
  • defaultPrevented: 布林值,表示是否呼叫過preventDefault()方法
  • detail: 整數,與事件相關的細節資訊
  • eventPhase: 整數,呼叫事件處理程式的階段,1表示捕獲階段,2表示目標階段,3表示冒泡階段
  • preventDefault(): 函式,取消事件的預設行為,cancelable為true時可以呼叫該方法
  • stopImmediatePropagation(): 函式,取消事件的進一步捕獲或冒泡,同時阻止任何事件處理程式被呼叫
  • stopPropagation(): 函式,取消事件的進一步捕獲或冒泡,bubbles為true時可以呼叫這個方法
  • target: 元素,事件的目標
  • trusted: 布林值,為true時表示事件是瀏覽器生成的,否則表示事件是通過JS建立的
  • type: 字串,被觸發的事件型別
  • view: 與事件關聯的抽象檢視,等同於發生事件的window物件

下面程式碼示例展示了上述部分屬性的用法,也可以幫助我們進一步理解事件流。假設頁面中有一個按鈕”myBtn”。當點選按鈕時,this和currentTarget都等於body元素,因為事件處理程式是註冊在body元素上。target的值卻等於按鈕元素,因為它是click事件的真正目標。由於按鈕上沒有註冊事件處理程式,結果”click”事件冒泡到了document.body那裡才得到處理。

document.body.onclick = function(event) {  console.log(event.currentTarget === document.body); // true  console.log(this === document.body); // true  console.log(event.target === document.getElementById("myBtn")); // true };

再看一個例子,下面程式碼中,stopPropagation()方法取消了事件的進一步捕獲或冒泡。當我點選按鈕時,本來應該會因為事件冒泡機制觸發按鈕和body元素上的點選事件處理程式,輸出”From Bth …”和”From Body …”。現在點選事件在按鈕元素上觸發之後就被阻止繼續在DOM層次中的傳播,因此body上的事件處理程式不會被觸發。

document.body.onclick = function(event) {  console.log(event.currentTarget === document.body); // true  console.log(this === document.body); // true  console.log(event.target === document.getElementById("myBtn")); // true };

7、Javascript Events: Event Listeners(事件監聽器)

DOM Level 2事件定義了兩個用於分配和刪除事件處理程式的方法:addeventlistener()和removeeventlistener ()。

這些方法存在於所有DOM節點上,並接受三個引數:要處理的事件名稱、事件處理函式和表示是否呼叫事件處理程式i的布林值。i.e 真與假。

事件監聽器有一個類似於事件處理程式的函式,不同的是,在將多個函式分配給同一個DOM元素和事件時,處理程式沒有限制。

在下面的演示中,指令碼使用addEventListener方法將handleMouseOver和handleMouseOut函式註冊為元素p的事件處理程式,其id值為content。

但是當您單擊按鈕時,方法removeEventListener將handleMouseOut函式與元素p分離。

示例:Javascript DOM:使用內聯事件處理事件

注意:onclick屬性用於設定用於單擊事件的處理程式。