javascript的事件監聽與捕獲和冒泡

html-js發表於2015-03-12

在前端開發中,我們經常需要對某些事件進行監聽。這樣只要在指定的元素上觸發了該事件,就會執行一個回撥來進行相關的操作。

而js中事件監聽方法總共有三種,分別如下所示:

  • element.addEventListener(type, listener[, useCapture]); // IE6~8不支援
  • element.attachEvent(’on’ + type, listener); // IE6~10,IE11不支援
  • element[’on’ + type] = function(){} // 所有瀏覽器

demo:

function cb() { console.log(1); }
element.addEventListener('click', cb, false);
element.attachEvent('onclick', cb);
element.onclick = cb;

引數含義:

  1.  type :事件型別
  2.  listener :事件觸發後的回撥函式
  3.  useCapture :是否使用捕獲,如果值為true, useCapture 表示使用者希望發起捕獲。 在發起捕獲之後, 只要Dom子樹下發生了該事件型別,都會先被該事件監聽器捕獲,然後再被派發到Dom子樹中的事件監聽器中。並且向上冒泡的事件不會觸發那些發起捕獲的事件監聽器。進一步的解釋可以檢視 DOM Level 3 Events 文件。 useCapture 預設值為 false 。

addEventListener 是W3C工作組在DOM Level 2開始引入的一個註冊事件監聽器的方法;而在此之前,傳統的事件監聽方法是通過 element[’on’ + type] 的方式來註冊的。

它們兩之間的主要區別是, element[’on’ + type] 的方式無法使用事件捕獲,並且 element[’on’ + type] 不支援對同一個元素的同一個事件註冊多個事件監聽器。如下面的例子所示,元素被點選後只會輸出1,而不會輸出0和1。

element.onclick = function(){ console.log(0); }
element.onclick = function(){ console.log(1); }

 

然而 addEventListener 方法在IE6~8的瀏覽器中不被支援。那麼在低版本的IE中怎麼來為同一個事件註冊多個事件監聽器呢?原來IE從IE5.0系列開始就引入了 attachEvent() 方法來支援這一特性。但遺憾的是該方法也不支援事件捕獲。並且從IE 11開始,這個方法已經被棄用。

 

談談事件的捕獲和冒泡

W3C規範中定義了3個事件階段,依次是捕獲階段、目標階段、冒泡階段。事件物件按照上圖的傳播路徑依次完成這些階段。如果某個階段不支援或事件物件的傳播被終止,那麼該階段就會被跳過。舉個例子,如果Event.bubbles屬性被設定為 false ,那麼冒泡階段就會被跳過。如果 Event.stopPropagation() 在事件派發前被呼叫,那麼所有的階段都會被跳過。

  • 捕獲 階段:在事件物件到達事件目標之前,事件物件必須從window經過目標的祖先節點傳播到事件目標。 這個階段被我們稱之為捕獲階段。在這個階段註冊的事件監聽器在事件到達其目標前必須先處理事件。
  • 目標 階段:事件物件到達其事件目標。 這個階段被我們稱為目標階段。一旦事件物件到達事件目標,該階段的事件監聽器就要對它進行處理。如果一個事件物件型別被標誌為不能冒泡。那麼對應的事件物件在到達此階段時就會終止傳播。
  • 冒泡 階段: 事件物件以一個與捕獲階段相反的方向從事件目標傳播經過其祖先節點傳播到window。這個階段被稱之為冒泡階段。在此階段註冊的事件監聽器會對相應的冒泡事件進行處理。

在一個事件完成了所有階段的傳播路徑後,它的 Event.currentTarget 會被設定為 null 並且 Event.eventPhase 會被設為0。 Event 的所有其他屬性都不會改變(包括指向事件目標的 Event.target 屬性)。

相關文章