JavaScript事件模型

一、什麼是事件?html

事件,就是文檔或瀏覽器窗口中發生的一些特定的交互瞬間。可使用偵聽器(或處理程序)來預訂事件,以便事件發生時執行相應的代碼。這種在傳統軟件工程中被稱爲觀察員模式的模型,支持頁面的行爲(JavaScript 代碼)與頁面的外觀(HTML 和CSS 代碼)之間的鬆散耦合。DOM2 級規範開始嘗試以一種符合邏輯的方式來標準化DOM事件。瀏覽器

二、什麼是事件流?函數

事件冒泡:IE 的事件流叫作事件冒泡(event bubbling),即事件開始時由最具體的元素(文檔中嵌套層次最深的那個節點)接收,而後逐級向上傳播到較爲不具體的節點(文檔)。如:this

1 <!DOCTYPE html>
2 <html>
3 <head>
4     <title>Event Bubbling Example</title>
5 </head>
6 <body>
7     <div id="myDiv">Click Me</div>
8 </body>
9 </html>

事件觸發順序爲:spa

事件捕獲:Netscape Communicator 團隊提出的另外一種事件流叫作事件捕獲(event capturing)。事件捕獲的思想是不太具體的節點應該更早接收到事件,而最具體的節點應該最後接收到事件。事件捕獲的用意在於在事件到達預約目標以前捕獲它。code

1 <!DOCTYPE html>
2 <html>
3 <head>
4     <title>Event Bubbling Example</title>
5 </head>
6 <body>
7     <div id="myDiv">Click Me</div>
8 </body>
9 </html>

事件觸發順序爲:htm

 「DOM2級事件」規定的事件流包括三個階段:事件捕獲階段、處於目標階段和事件冒泡階段。首先發生的是事件捕獲,爲截獲事件提供了機會。而後是實際的目標接收到事件。最後一個階段是冒泡階段,能夠在這個階段對事件作出響應。如:對象

1 <!DOCTYPE html>
2 <html>
3 <head>
4     <title>Event Bubbling Example</title>
5 </head>
6 <body>
7     <div id="myDiv">Click Me</div>
8 </body>
9 </html>

總事件觸發順序爲:blog

三、什麼是事件處理程序?seo

事件就是用戶或瀏覽器自身執行的某種動做。諸如click、load 和mouseover,都是事件的名字。而響應某個事件的函數就叫作事件處理程序(或事件偵聽器)。事件處理程序的名字以"on"開頭,所以click 事件的事件處理程序就是onclick,load 事件的事件處理程序就是onload。爲事件指定處理程序的方式有好幾種。

 3.1 、DOM0級事件處理程序

經過JavaScript 指定事件處理程序的傳統方式,就是將一個函數賦值給一個事件處理程序屬性。這種爲事件處理程序賦值的方法是在第四代Web 瀏覽器中出現的,並且至今仍然爲全部現代瀏覽器所支持。緣由一是簡單,二是具備跨瀏覽器的優點。要使用JavaScript 指定事件處理程序,首先必須取得一個要操做的對象的引用。綁定"onclick"方法,如:

1 var btn = document.getElementById("myBtn");
2 btn.onclick = function(){
3     alert("Clicked");
4 };

解除綁定"onclick"方法,如:

1 btn.onclick = null;

 

3.二、DOM2 級事件處理程序

「DOM2級事件」定義了兩個方法,用於處理指定和刪除事件處理程序的操做:addEventListener()removeEventListener()。全部DOM節點中都包含這兩個方法,而且它們都接受3 個參數:要處理的事件名、做爲事件處理程序的函數和一個布爾值。最後這個布爾值參數若是是true,表示在捕獲階段調用事件處理程序;若是是false,表示在冒泡階段調用事件處理程序。

要在按鈕上爲click 事件添加事件處理程序(冒泡),可使用下列代碼:

1 var btn = document.getElementById("myBtn");
2 btn.addEventListener("click", function(){
3     alert(this.id);
4 }, false);

上面的代碼爲一個按鈕添加了onclick 事件處理程序,並且該事件會在冒泡階段被觸發(由於最後一個參數是false)。與DOM0 級方法同樣,這裏添加的事件處理程序也是在其依附的元素的做用域中運行。使用DOM2 級方法添加事件處理程序的主要好處是能夠添加多個事件處理程序。來看下面的例子。

1 var btn = document.getElementById("myBtn");
2 btn.addEventListener("click", function(){
3     alert(this.id);
4 }, false);
5 btn.addEventListener("click", function(){
6     alert("Hello world!");
7 }, f alse);

這裏爲按鈕添加了兩個事件處理程序。這兩個事件處理程序會按照添加它們的順序觸發,所以輸出:

1 myBtn
2 Hello world!

經過addEventListener()添加的事件處理程序只能使用removeEventListener()來移除;移除時傳入的參數與添加處理程序時使用的參數相同。這也意味着經過addEventListener()添加的匿名函數將沒法移除。

匿名函數將沒法移除,以下面的例子所示。

 1 var btn = document.getElementById("myBtn");
 2 btn.addEventListener("click", function(){
 3     alert(this.id);
 4 },false);
 5 
 6 //這裏省略了其餘代碼
 7 
 8 btn.removeEventListener("click", function(){ //沒有用!
 9     alert(this.id);
10 }, false);

在這個例子中,咱們使用addEventListener()添加了一個事件處理程序。雖然調用removeEventListener()時看似使用了相同的參數,但實際上,第二個參數與傳入addEventListener()中的那一個是徹底不一樣的函數。而傳入removeEventListener()中的事件處理程序函數必須與傳入addEventListener()中的相同,以下面的例子所示。

正確作法是,請看下面例子:

1 var btn = document.getElementById("myBtn");
2 var handler = function(){
3     alert(this.id);
4 };
5 btn.addEventListener("click", handler, false);
6 //這裏省略了其餘代碼
7 btn.removeEventListener("click", handler, false); //有效!

重寫後的這個例子沒有問題,是由於在addEventListener()和removeEventListener()中使用了相同的函數。

3.2.一、IE事件處理程序

IE 實現了與DOM 中相似的兩個方法:attachEvent()detachEvent()。這兩個方法接受相同的兩個參數:事件處理程序名稱與事件處理程序函數。因爲IE8 及更早版本只支持事件冒泡,因此經過attachEvent()添加的事件處理程序都會被添加到冒泡階段

要使用attachEvent()爲按鈕添加一個事件處理程序,可使用如下代碼。

1 var btn = document.getElementById("myBtn");
2 btn.attachEvent("onclick", function(){
3     alert("Clicked");
4 });

注意,attachEvent()的第一個參數是"onclick",而非DOMaddEventListener()方法中的"click"。

在IE 中使用attachEvent()與使用DOM0 級方法的主要區別在於事件處理程序的做用域。在使用DOM0 級方法的狀況下,事件處理程序會在其所屬元素的做用域內運行;在使用attachEvent()方法的狀況下,事件處理程序會在全局做用域中運行,所以this 等於window。來看下面的例子。

1 var btn = document.getElementById("myBtn");
2 btn.attachEvent("onclick", function(){
3     alert(this === window); //true
4 });

與addEventListener()相似,attachEvent()方法也能夠用來爲一個元素添加多個事件處理程序。來看下面的例子。

1 var btn = document.getElementById("myBtn");
2 btn.attachEvent("onclick", function(){
3     alert("Clicked");
4 });
5 btn.attachEvent("onclick", function(){
6     alert("Hello world!");
7 });

輸出:

1 Hello world!
2 Clicked

這裏調用了兩次attachEvent(),爲同一個按鈕添加了兩個不一樣的事件處理程序。不過,與DOM方法不一樣的是,這些事件處理程序不是以添加它們的順序執行,而是以相反的順序被觸發。單擊這個例子中的按鈕,首先看到的是"Hello world!",而後纔是"Clicked"。

使用attachEvent()添加的事件能夠經過detachEvent()來移除,條件是必須提供相同的參數。與DOM 方法同樣,這也意味着添加的匿名函數將不能被移除。不過,只要可以將對相同函數的引用傳給detachEvent(),就能夠移除相應的事件處理程序。例如:

1 var btn = document.getElementById("myBtn");
2 var handler = function(){
3     alert("Clicked");
4 };
5 btn.attachEvent("onclick", handler);
6 //這裏省略了其餘代碼
7 btn.detachEvent("onclick", handler);

注:支持該事件處理程序的只有IE和Opera


3.2.二、跨瀏覽器的事件處理程序

只需關注冒泡階段。第一個要建立的方法是addHandler(),它的職責是視狀況分別使用DOM0 級方法、DOM2 級方法或IE 方法來添加事件。這個方法屬於一個名叫EventUtil 的對象,本書將使用這個對象來處理瀏覽器間的差別。addHandler()方法接受3 個參數:要操做的元素、事件名稱和事件處理程序函數

addHandler()對應的方法是removeHandler(),它也接受相同的參數。這個方法的職責是移除以前添加的事件處理程序——不管該事件處理程序是採起什麼方式添加到元素中的,若是其餘方法無效,默認採用DOM0 級方法。

EventUtil 的用法以下所示。

 1 var EventUtil = {
 2     addHandler: function(element, type, handler){
 3         if (element.addEventListener){
 4             element.addEventListener(type, handler, false);
 5         } else if (element.attachEvent){
 6             element.attachEvent("on" + type, handler);
 7         } else {
 8             element["on" + type] = handler;
 9         }
10     },
11     removeHandler: function(element, type, handler){
12         if (element.removeEventListener){
13             element.removeEventListener(type, handler, false);
14         } else if (element.detachEvent){
15             element.detachEvent("on" + type, handler);
16         } else {
17             element["on" + type] = null;
18         }
19     }
20 };    

能夠像下面這樣使用EventUtil 對象:

1 var btn = document.getElementById("myBtn");
2 var handler = function(){
3     alert("Clicked");
4 };
5 EventUtil.addHandler(btn, "click", handler);
6 //這裏省略了其餘代碼
7 EventUtil.removeHandler(btn, "click", handler);

今天的討論就到這裏,若是有什麼意見或者建議,請多留言哦!!!

相關文章
相關標籤/搜索