【原創翻譯】深入理解javascript事件處理函數綁定三部曲(二)——傳統處理函數綁定模型

來源:互聯網
上載者:User


原文地址

這一次我要解釋最優秀的事件處理函數綁定方式:確保當事件發生在某個html元素上時,能有相應的指令碼與之對應

 

在早期運行javascript的瀏覽器中,處理函數綁定只能通過行內模型。但自從DHTML徹底改變產生網頁的方式後,事件綁定模型也得到拓展並且更加靈活。所以瀏覽器廠商引進了新的事件模型。Netscape是從第三代開始的,而IE在第四代中也同樣引進。

 

因為Netscape3已經支援新的綁定模型,所以至少在瀏覽器大戰之前,從某種意義上來說它已經是一種執行的標準,。因此,微軟為了使它的瀏覽器具有相容性(因為大多數網頁都遵循了Netscape的事件模型),最後一次不得不也採用了這種標準。

 

所以兩家瀏覽器,事實上是所有的瀏覽器,都認可這段代碼:

element.onclick = doSomething;

 

作為一種綁定事件函數的正確方式。無論使用者什麼時候在什麼瀏覽器上點擊這個HTML元素,函數,doSomething()都會被執行。因為這種寫法是通用,更因為它是跨瀏覽器綁定事件函數的唯一方式。但有一點非常重要,就是你也要非常明白這種方式的局限性和應該出現的場合。

 

因為當這種模型被引進時沒有任何的官方標準可以遵循,所以我把它稱為傳統事件綁定模型。與此同時W3C已經標準化了事件綁定,並且微軟也發明了更先進的模型(參見下一篇),但是傳統的模型仍然能良好的工作。

 

更先進的事件綁定

在Netscape3和Explorer4之後,javascript對每一種可以發生在元素上的事件,都作為自己的一種屬性。因此HTML元素有onclick,onmouseover,onkeypress屬性等。但究竟哪一種html元素有哪一種屬性,哪一種html元素支援事件——依據瀏覽器而定。

 

就這些屬性而言,並不是什麼很新鮮的東西。在早期的javascript瀏覽器中已經存在了:

<a href="somewhere.html" onclick="doSomething()">

 

這個A標籤有一個onclick屬性,也就意味著javascript變成了一種元素的屬性。在早期的瀏覽器中,處理函數用這種寫入標籤的方式。所以如果你想在頁面上的每一個超連結都有同樣的處理函數,工作量是非常巨大的。

 

隨著傳統綁定模型的出現,onclick,onmouseover等所有html元素的事件屬性都可以通過javascript訪問。在你通過DOM訪問html元素後,現在你可以在最小程度的修改html代碼的基礎上,新增,修改或者移除處理函數。你可以把你的函數寫入html的屬性中:

element.onclick = doSomething;

 

在我們的例子中,函數doSomething()綁定到onclick屬性上,並且無論使用者點擊這個元素,函數都會被執行。注意事件名稱必須小寫。

 

要移除處理函數,只要簡單的把onclick方法置空

element.onclick = null;

 

處理函數也是一個普通的javascript函數,就算事件沒有發生它也能被執行,如果你這麼作:

element.onclick()

 

doSomething()將被執行,雖然沒有事件真的發生。但是這種執行處理函數的方式使用的並不非常多

 

微軟也為自己的IE5.5和之後的IE新增了fireEvent()方法,目的是為了實現上面的效果。

文法應該這麼寫

element.fireEvent('onclick')

 

沒有括弧!

請注意在綁定處理函數過程中不能使用括弧()。分配給onclick給它的是整個函數。如果你這麼做:

element.onclick = doSomething();

函數將會被執行,卻是它的結果被綁定在onclick上。這並不是我們想要的,我們希望當事件發生時函數被執行。再者說,通常函數是期望有相應的事件發生,如果在沒有內容相關的情況下就執行它,會引起錯誤。

 

this關鍵字

在javascript中this關鍵字總是對一個函數“擁有者”的引用。在處理函數的例子中,如果this是代指正在處理事件的html元素,這將會非常有用。你可以很輕鬆的訪問它。

 

不幸的是this關鍵字雖然非常強大,但是如果你不是非常清楚它的工作原理的話,使用起來也很困難。我在另一篇文章中有談論。這裡我只給出一個簡短的結論。

 

在傳統繫結模式中的this關鍵字,同行內繫結模式(上一篇)中的有所不同。在這裡this關鍵字存在於函數中,而不是Html某個屬性。具體的不同之處會在另一個頁面單獨指出

element.onclick = doSomething;

another_element.onclick = doSomething;

function doSomething() {

this.style.backgroundColor = '#cc0000';

}

如果你給任何一個Html元素的click事件綁定一個doSomething()函數,則使用者在任何時候點擊它時。它的背景都會變為紅色。

 

匿名函數

假設你想在改變所有DIV的背景顏色,在onmouseover是改變在onmouseout時恢複,恰當的this應該這麼使用:

var x = document.getElementsByTagName('DIV');

for (var i=0;i<x.length;i++) {
x[i].onmouseover = over;
x[i].onmouseout = out;
}

function over() {
this.style.backgroundColor='#cc0000'
}

function out() {
this.style.backgroundColor='#ffffff'
}

代碼當然能正常工作,但是over()和out()函數這麼簡單,把他們綁定為匿名函數更為明智:

...

for (var i=0;i<x.length;i++) {
x[i].onmouseover = function () {this.style.backgroundColor='#cc0000'}

x[i].onmouseout = function () {this.style.backgroundColor='#ffffff'}
}

onmouseover和onmouseoout期望能匹配對應的處理函數,相比複製over()和out()函數而言,我們在事件綁定指令碼中立即定義了處理函數。因為他們沒有函數名,所以稱之為匿名函數。

 

這兩種綁定事件處理函數的方法是完全相同的的,唯一的不同之處是第二個用更少的代碼。當我需要綁定一個簡單的事件處理函數時,我更樂意使用匿名函數。

 

問題

傳統模式的一個明顯缺陷的就是onclick只能容下一個函數,那麼當你想為一個事件綁定多個處理函數時這就變成了一個大問題。

 

舉個例子,假設你在寫一個功能模組,實現一個元素的拖拽。模組藉助於一個onclick處理函數上,當點擊這個元素時開始執行拖拽。你同時也在實現另一個模組,能悄悄追蹤使用者的點擊情況,並且在發生onunload事件時,把資訊發送給伺服器,你就可以發現使用者到底是如何使用你的頁面的。這個模組,同樣藉助於onclick處理函數。

 

所以你可以這麼做:

element.onclick = startDragDrop;
element.onclick = spyOnUser;

 

但是問題發生了。第二個綁定onclick上的函數會覆蓋第一個函數,所以當使用者點擊某個元素時,只有第二個spyOnUser被執行。解決方案當然是綁定一個能同時執行兩個函數的函數

element.onclick = function () {startDragDrop(); spyOnUser()}

 

更靈活的綁定方式

但是假設你不需要在每一個頁面都需要這兩個功能。現在如果你真的這麼做:

element.onclick = function () {startDragDrop(); spyOnUser()}

 

你也許會得到錯誤的資訊,因為這兩個函數的其中之一可能還沒有定義。當我們想要綁定spyOnUser()時,startDrapDrop()可能還沒有綁定,所以我們這麼做:

var old = (element.onclick) ? element.onclick : function () {};

element.onclick = function () {old(); spyOnUser()};

首先你要定義一個名為old的變數,如果這個元素有一個onclick事件處理函數,把這個函數儲存於old中,如果它沒有,把一個空函數放進old中。再給div元素繫結一個新的處理函數,它首先執行的是old,再是spyOnUser()

 

現在新的事件處理函數添加給元素了,並且之前的處理(如果有的話)還能得以儲存

 

還有最後一個問題:如果你想移除其中一個處理函數,而不是全部的,應該怎麼辦?現在我不知道應該如何是好了。你又不得不以另一種方式再次編輯element.onclick事件,但是我並不想真的去研究這個問題

 

其他的模型

現在我們已經見識到傳統的事件綁定模型使用起來非常簡單,但是也存在一些棘手的問題,比如說當你想給同一個事件添加不止一個處理函數時。所以W3C事件綁定模型很好的解決了這個問題

 

下篇繼續談《先進的綁定模型》

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在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.