javascript 事件處理

來源:互聯網
上載者:User

javascript 事件處理

【寫在前面】最近一直在看js的基礎,畢竟jquery雖然好用,總歸是用著別人寫的,只會用api不如搞清楚實現的原理。等把js基礎鞏固好了一定要去讀jquery的源碼。

事件流

事件流描述的是從頁面中接收事件的順序。js中有兩種事件流,冒泡流和捕獲流。兩種流的名稱都很形象,在由節點構成的一顆html樹上面,冒泡流指事件開始時候由最具體的元素最先接收,然後逐級傳播到最不具體的節點,比如在如下文檔中:

 

當單擊div時,事件首先在div上響應,然後傳到body元素上,然後傳到html元素上,最後傳到document對象。
捕獲流正好相反,最先響應的是document對象,然後沿dom樹依次向下,到html,到body,最後到實際目標,也就是div。
老版瀏覽器並不支援捕獲流,冒泡流也非常符合我們對事件傳播的理解,因此我們更多使用的是冒泡流。

事件處理的幾種方法

在js的事件處理中定義了很多種事件,事件名稱是指具體的某種動作,比如click、load、mouseover等都是事件的名稱。而響應某個事件的函數叫事件處理常式,事件處理常式的名字是以on開頭的,因此click事件的事件處理常式就是onclick,load事件的事件處理常式就是onload。

標籤內綁定

通過設定標籤的屬性可以為節點十分方便地綁定事件,如:

也可以調用其他地方定義的指令碼:

<script>    function showMessage(){        alert(按鈕按下);    }</script>...

使用直接綁定有兩個特別的地方,其一是會建立一個封裝元素屬性的函數,這個函數中有一個局部變數event,也就是事件對象:

事件產生時,event對象自動傳遞到showMessage函數中,通過這個對象我們可以訪問到事件對象的很多屬性。另外在事件處理常式內部,this指代事件的目標元素,比如

另外噹噹前元素是一個表單元素時,則範圍中還會包含表單元素的入口,也就是說在事件處理常式中可以訪問其他表單元素,例如


這樣可以直接輸出username中的值。

然而通過這種方式添加的事件處理雖然直觀方便,但有很多壞處:
(1)因為頁面載入順序是從上往下,如果綁定的指令碼寫在html下面,可能使用者點擊元素的時候指令碼還未執行,造成使用者點半天沒反應,如:

......//很多內容...<script>    function showMessage(){        //...    }</script>

(2)html和js代碼緊密結合,比如showMessage這個方法,如果介面內很多元素都通過這種方式綁定了這個方法,那麼如果某一刻想給這個函數換一個名字時,你需要同時改動很多處地方,相當麻煩。

DOM0級處理常式

第二種方式是在js中為元素繫結事件,通過在js中擷取元素,然後給其指定事件:

var btn = document.getElementById(button);btn.onclick = function(){    alert(this.id);}

通過DOM0級方法指定的程式被認為是元素的方法,所以上述代碼執行後,按下元素彈出的將是按鈕的id,可以通過this擷取該元素所有的屬性和方法。
需要刪除通過DOM0級方法指定的事件處理常式,只需將該屬性值設為null即可:

btn.onclick = null;

需要注意的是通過這種方式不能為元素添加重複事件,多次為onclick賦值只有最後一個是有效,比如

btn.onclick = function(){    alert(first);}btn.onclick = function(){    alert(second);}

最後單擊按鈕的時候只會輸出second。

DOM2級處理常式

IE9、Firefox、chrome、safari和opera支援DOM2級事件處理常式
“DOM2級事件”定義了兩個方法,用於指定和刪除事件處理常式的操作:addEventListener()和removeEventListener()。所有DOM節點都有這個方法,並接收3個參數:事件名、事件處理函數和一個布爾值。這個布爾值代表了是使用捕獲還是冒泡,true代表在捕獲階段處理,false代表在冒泡階段處理,不填預設是false。

var btn = document.getElementById(button);btn.addEventListener(click, function(){    //...}, false);

和DOM0級事件處理不同,通過這種方法綁定的事件處理可以多次添加,比如

var btn = document.getElementById(button);btn.addEventListener(click, function(){    alert(first);}, false);btn.addEventListener(click, function(){    alert(this.id);}, false);

而且在函數內this同樣指代目標元素,點擊按鈕後會先輸出first,再輸出該btn的id。
通過addEventListener添加的事件只能通過removeEventListener移除,而且參數必須一樣(三個參數一模一樣),這代表使用匿名函數綁定的事件是無法移除的,最好將事件處理函數單獨定義。

btn.addEventListener(click, function(){    alert(first);}, false);btn.removeEventListener(click, function(){    alert(first);}, false); //沒有效果btn.addEventListener(click, showMessage, false);btn.removeEventListener(click, showMessage, false); //移除成功
IE事件處理常式

IE中單獨實現了與DOM2級事件處理中類似的兩個方法:attachEvent和detachEvent()。這兩個方法接收兩個參數:事件處理常式名稱和事件處理函數。因為IE8及更早版本只支援事件冒泡,所以通過這種方式添加的事件處理常式都會被添加在事件冒泡階段。

var btn = document.getElementById(button);btn.attachEvent(onclick, function(){ //注意是onclick    alert(first);});

IE事件處理同之前的其他方式有兩個區別,第一,IE的事件處理常式會在全域環境下運行。
這代表在其中使用this會等於window。

var btn = document.getElementById(button);btn.attachEvent(onclick, function(){    alert(this === window);  //true});

第二,多次添加的事件處理函數按添加的相反順序執行,比如

var btn = document.getElementById(button);btn.attachEvent(onclick, function(){    alert(first);});btn.attachEvent(onclick, function(){    alert(second);});

當按下按鈕時,將先輸出second,然後才輸出first。
要移除事件的方式同DOM2級相似,調用detachEvent然後傳如相同參數即可。

編寫跨瀏覽器的事件處理常式

上面提到IE和其他瀏覽器在處理事件上還是存在一些差異的,可以編寫一個EventUtil對象,來將添加事件和移除事件封裝起來。
實現方式是先判斷是否支援DOM2級處理,如果不支援採用IE方法,如果都不支援最後採用DOM0級方法。

var EventUtil = {    //添加事件    addHandler: function(element, type, handler){        if(element.addEventListener){            //支援DOM2級            element.addEventListener(type, element, handler);        }else if(element.attachEvent){            //IE事件處理,注意on首碼            element.attachEvent(on + type, handler);        }else{            //DOM0級            element[on + type] = handler;        }    },    //移除事件    removeHandler: function(){        if(element.removeEventListener){            //支援DOM2級            element.removeEventListener(type, element, handler);        }else if(element.detachEvent){            //IE事件處理,注意on首碼            element.detachEvent(on + type, handler);        }else{            //DOM0級            element[on + type] = null;        }    }}

 

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.