DOM事件流

Pomelo1213發表於2018-02-01

事件流描述的是從頁面中接收事件的順序。說白了,我做了一件事,這件事怎麼被別人知道的,這個順序就是事件流。 但是對於這個順序,有些人產生了分歧。IE和Netscape提出了幾乎是完全相反的事件流的概念。於是有了(IE)事件冒泡流和(Netscape)事件捕獲流。


事件冒泡

事件冒泡:事件開始時由最具體的元素(文件中巢狀層次最深的那個節點)接收,然後逐級向上傳播到較為不具體的節點(文件)。 如下示例:

<!DOCTYPE html>
<html>
    <head>
        <title>事件冒泡</title>
    </head>
    <body>
        <div id="myDiv">點我</div>
    </body>
</html>
複製程式碼

如果你點選了裡面的<div>元素,那麼click事件就會按照下面的順序傳播執行:

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

click事件會首先在<div>元素身上發生,這個元素就是我們點選的的元素,然後才是上一層元素,一直到document元素。

DOM事件流


事件捕獲

事件捕獲:不太具體的節點應該更早接收事件,而最具體的節點應該是最後接收到事件。那麼點選<div>元素就會以下列順序執行click事件:

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

事件捕獲過程,document物件首先接收到click事件,然後依次向下,傳播到事件的實際目標。

DOM事件流

DOM事件流

事件流規定包含三個流程:事件捕獲階段,事件冒泡階段和處於目標階段。首先發生是事件捕獲(截獲事件),然後是處於目標階段接收到事件,最後是事件冒泡階段(對事件作出相應)。

DOM事件流

在DOM事件流中,目標元素<div>在事件捕獲階段是不會接受到事件的,下一階段“處於目標階段”,事件在<div>上發生,並在事件處理中被看成冒泡階段的一部分,然後,冒泡階段發生,事件傳播迴文件。


如何用事件流

在上文中的事件處理,就是我們使用事件流的一種方法,事件是使用者或者瀏覽器自身執行的某種動作,例如'click'、'mouseover'等都是事件的名字,而相應這種操作的函式就叫事件處理程式(事件偵聽)。

  • DOM0級處理事件程式

    通過JavaScript指定事件處理程式的傳統方法,就是將一個函式賦值給一個事件處理程式屬性。每個元素(包括window和document)都有自己的事件處理程式屬性,這些屬性全部小寫。如下:

    var button = document.getElementById('myButton')
    button.onclick = function(){
        alert('hello'+this.id)
    }
    複製程式碼

    我們通過文件物件獲取到一個button的引用,並給它了一個onclick的事件處理程式。但是需要注意的是:如果這段程式碼執行在button的後面,可能會出現你怎麼點選都沒有反應。

    DOM0級方法指定的事件處理程式被認為是元素的方法。因此,這個時候的事件處理程式是在該元素的作用域中執行。所以程式碼塊裡面會alert出‘myButton’,往大了說,在這個事件處理程式的作用域中,可以用this訪問到該元素的任何方法和屬性。這種方式新增的事件處理程式會在事件流的冒泡階段被處理。

    如果想要刪除這個DOM0級事件處理程式,如下:

    button.onclick = null
    複製程式碼

    再點選就不會有任何反應。

  • DOM2級事件處理程式

    DOM2級事件處理程式定義了兩個方法:‘addEventListener()’和‘removeEventListener()’,所有DOM節點都包含這兩個方法,並且它們接收3個引數:要處理的事件名、事件處理的函式、一個布林值。

    • 布林值為true,表示在事件捕獲階段執行事件處理程式
    • 布林值為false,表示在事件冒泡階段執行事件處理程式
    • 如果不寫布林值,預設為false 示例:
    var button = document.getElementById('myButton')
    button.addEventListener('click', function(){
      alert('hello'+this.id)  
    }, false)
    複製程式碼

    和DOM0級事件處理程式一樣,這個this.id列印還是‘myButton’,其作用域仍然在依附的元素中。使用DOM2級事件處理程式的好處是可以新增多個事件,那麼事件就會按照新增它們的順序執行。

    通過addEventListener()新增的時間處理程式,只能通過removeEventListener()來刪除。

    button.removeEventListener('click', function(){
      alert('hello'+this.id)  
    }, false)
    複製程式碼

    上面這樣做是沒有用的,因為removeEventListener(),需要傳入一樣的引數,表面上你確實引數傳的一樣,其實不然,裡面有個匿名函式,所以你的第二引數永遠都不會一樣。

    var button = document.getElementById('myButton')
    var pomelo = function(){
      alert('hello'+this.id)  
    }
    button.addEventListener('click', pomelo, false)
    button.removeEventListener('click', pomelo, false)
    複製程式碼

    上面這樣才是真正的刪除了。

大多數情況下,都是將事件處理程式新增到事件流的冒泡階段,如果不是特別的需求,建議新增到冒泡階段。

相關文章