1. 程式人生 > >JavaScript高階程式設計學習筆記之事件

JavaScript高階程式設計學習筆記之事件

1、事件流
事件流描述的是從頁面中接收事件的順序。

事件冒泡
IE的事件流叫做事件冒泡(event bubbling),即事件開始時由最具體的元素(文件中巢狀層次最深的那個節點)接收,然後逐級向上傳播到較為不具體的節點(文件)。(DOM樹向上傳播)(通俗解釋(個人理解: 當一個元素上的事件被觸發的時候,比如說滑鼠點選了一個按鈕,同樣的事件將會在那個元素的所有祖先元素中被觸發。這 一過程被稱為事件冒泡;這個事件從原始元素開始一直冒泡到DOM樹的最上層。))

事件冒泡的優點與缺點
優點:想象一下現在我們有一個10列、100行的HTML表格,你希望在使用者點選 表格中的某一單元格的時候做點什麼。比如說我有一次就需要讓表格中的每一個單元格在被點選的時候變成可編輯狀態。如果把事件處理器加到這1000個單元格 會產生一個很大的效能問題,並且有可能導致記憶體洩露甚至是瀏覽器的崩潰。相反地,使用事件代理的話,

致辭英文你只需要把一個事件處理器新增到table元素上就可 以了,這個函式可以把點選事件給截下來,並且判斷出是哪個單元格被點選了。
1.那些需要建立的以及駐留在記憶體中的事件處理器少了。
這是很重要的一點,這樣我們就提高了效能,並降低了崩潰的風險。
2.在DOM更新後無須重新繫結事件處理器了。
如果你的頁面是動態生成的,比如說通過Ajax,你不再需要在元素被載入或 者解除安裝的時候來新增或者刪除事件處理器了。
潛在的問題也許並不那麼明顯,但是一旦你注意到這些問題,你就可 以輕鬆地避免它們:你的事件管理程式碼有成為效能瓶頸的風險,所以盡 量使它能夠短小精悍。

缺點:不是所有的事件都能冒泡。blur、focus、load和unload不能像其它事件一樣冒泡。事 實上blur和focus可以用事件捕獲而非事件冒泡的方法獲得(在IE之外的其它瀏覽器中)。需要注意的是:如果你的程式碼處理mousemove事件的話你遇上效能瓶頸的風險可就大了,因為mousemove事件觸發非常頻繁。而mouseout則因為其 怪異的表現而變得很難用事件代理來管理。

事件捕獲
事件捕獲的思想是不太具體的節點應該更早的接收到事件,而最具體的節點應該在最後接收到節點。事件捕獲的用意在於事件到達預定目標之前捕獲它。

DOM事件流
“DOM2級事件流”規定的事件流包括三個階段:事件捕獲階段、處於目標階段和冒泡階段。首先發生的是事件捕獲,為截獲事件提供了機會。然後是實際的目標接收到事件。最後一個階段是冒泡階段,可以在這個階段對事件作出響應。以簡單的HTML頁面為例,單擊< div>元素會按照下圖順序觸發事件

這裡寫圖片描述

在DOM事件流中,實際的目標(

元素)在捕獲階段不會接收到事件。這意味著在捕獲階段,事件從document到再到後就停止了。下一個階段是“處於目標”階段,於是事件在
上發生,並在事件處理中被看成冒泡階段的一部分。然後冒泡階段發生,事件又傳播迴文檔。

 

多數支援DOM事件流的瀏覽器都實現了一種特定行為;即使“DOM2級事件”規範明確要求捕獲階段不會涉及事件的目標,但Safari、Chrome、Firefox和Opera9.5及更高版本都會在捕獲階段觸發事件物件上的事件。結果,就是有兩個機會在目標物件上面操作事件。

2.事件處理程式(事件偵聽器)
事件是使用者或瀏覽器自身執行的某種動作。諸如click、load和mouseover,都是事件的名字。 而響應某個事件的函式就叫做事件處理程式(或事件偵聽器)。事件處理程式的名字以“on”開頭,因此click事件的事件處理程式就是onclick等。為事件指定處理程式的方式有好幾種。

HTML事件處理程式
某個元素支援的每種事件,都可以使用一個與相應事件處理程式同名的HTML特性指定。同義詞替換這個特性的值應該是能夠執行的JavaScript程式碼。例如,要在按鈕被單擊時執行一些JavaScript,可以像下面這樣編寫程式碼:

當單擊這個按鈕時,就會顯示一個警示框。這個操作是通過指定onclick特性並將一些JavaScript程式碼作為它的值來定義的。由於這個值是JavaScript,因此不能在其中使用未經轉義的HTML語法字元。

在HTML中定義事件處理程式可以包含要執行的具體動作,也可以呼叫在頁面其他地方定義的指令碼,例如:

在HTML中指定事件有兩個缺點。首先,存在一個時差問題。因為使用者可能在HTML元素一出現在頁面上就觸發相應的事件,但當時事件處理程式有可能尚不具備執行條件。例如前面的例子,假設showMessage函式在按鈕下方頁面最底部定義的,如果使用者在頁面解析showMessage函式之前就單擊了按鈕,就會引發報錯。第二個確定是HTML與JavaScript程式碼緊密耦合。如果要更換事件處理程式,就要改動兩個地方。

DOM0級事件處理程式
通過JavaScript指定事件處理程式的傳統方式,就是講一個函式賦值給一個事件處理程式屬性。要使用JavaScript指定事件處理程式,首先必須取得一個要操作的物件的引用。每個元素(包括window和document)都有自己的事件處理程式屬性,這些屬性通常小寫,例如onclick。將這種屬性的值設定成一個函式,就可以指定事件處理程式。趙雯使用DOM0級方法指定的事件處理程式被認為是元素的方法,因此是在元素的作用域中執行,換句話說,程式中的this引用當前元素。

可以在事件處理程式中通過this訪問元素的任何屬性和方法,以這種方式新增的事件處理程式會在事件流中的冒泡階段被處理。可以刪除通過DOM0級方法指定的事件處理程式,只要將事件處理程式屬性的值設為null即可。

DOM2級事件處理程式

“DOM2級事件”定義了兩個方法,用於處理指定和刪除事件處理程式的操作:addEventListener()和removeEventListener()。所有DOM節點中都包含這兩個方法,並且它們都接受3個引數:要處理的事件名、作為事件處理程式的函式和一個布林值。最後這個布林值如果是true,表示在捕獲階段呼叫事件處理程式;如果是false,表示在冒泡階段呼叫事件處理程式。

要在按鈕上為click事件新增事件處理程式,可以使用如下程式碼:

上面的程式碼為一個按鈕添加了onclick事件處理程式,而且該事件會在冒泡階段被觸發。英語入門學習與DOM0級方法一樣,這裡新增的事件處理程式也是在其依附的元素的作用域執行。使用DOM2級方法新增事件處理程式的主要好處是可以新增多個事件處理程式。

這裡為按鈕多添加了兩個事件處理程式。這兩個事件處理程式會按照新增它們的順序觸發,因此首先會顯示元素ID,其次會顯示“Hello World!”訊息。

通過addEventListener()新增的事件處理程式只能使用removeEventListener來移除;移除時傳入的引數與新增處理程式時使用的引數相同。這也意味著通過addEventListener()新增的匿名函式將無法移除,如下:

大多數情況下,都是將事件處理程式新增到事件流的冒泡階段,這樣可以最大限度的相容各種瀏覽器。最好只在需要事件到達目標之前截獲它的時候將事件處理程式新增到捕獲階段。如果不是特別需要,我們不建議在事件捕獲階段註冊事件處理程式。

IE事件處理程式

IE實現了與DOM類似的兩個方法:attachEvent()和detachEvent()。這兩個方法接受相同的兩個引數:事件處理程式名稱與事件處理程式函式。由於IE只支援事件冒泡,所以通過attachEvent()新增的事件處理程式都會被新增到冒泡階段。

在IE中使用attachEvent()與使用DOM0級方法的主要區別在於事件處理程式的作用域。零基礎英語入門學習DOM0級事件處理程式會在其所屬元素的作用域內執行;在使用attachEvent()方法的情況下,事件處理程式會在全域性作用域中執行,因此this等於window。在編寫跨瀏覽器的程式碼時,牢記這一點區別非常重要

attachEvent()也可以為一個元素新增多個事件處理程式,來看下面的例子:

與DOM方法不同的是,這些事件處理程式不是以新增它們的順序執行,而是以相反的順序被觸發。單擊這個例子中的按鈕,首先看到的是“Hello World!”,然後才是“Clicked”。使用attachEvent()新增的事件可以通過detachEvent()來移除,條件是必須提供相同的引數。與DOM方法一樣,新增的匿名函式將不能被移除。

事件是JavaScript中最重要的主題之一,深入理解事件的工作機制以及它們對效能的影響至關重要。