事件使得客戶端的 JavaScript 有機(jī)會(huì)被激活,并得以運(yùn)行。在一個(gè) Web 頁面裝載之后,運(yùn)行腳本的唯一方式,就是響應(yīng)系統(tǒng)或者用戶的動(dòng)作。雖然從第一個(gè)支持腳本編程的瀏覽器面世以來,簡(jiǎn)單的事件被實(shí)現(xiàn)為 JavaScript 的一部分;但是大多數(shù)最近出現(xiàn)的瀏覽器都實(shí)現(xiàn)了強(qiáng)壯的事件模型,使腳本可以更加智能地處理事件。現(xiàn)在的問題在于:為了支持各種瀏覽器,您必須和多個(gè)先進(jìn)的事件模型做斗爭(zhēng),準(zhǔn)確地說,是三個(gè)。

          這三個(gè)事件模型分別和下面的文檔對(duì)象模型(Document Object Model,即 DOM)三巨頭結(jié)盟:Netscape Navigator 4 (NN4),Macintosh 和 Windows 系統(tǒng)的 Internet Explorer 4 及其更新版本(IE4+),以及在 Safari 中得到實(shí)現(xiàn)的 W3C DOM。盡管這些模型之間有些地方存在一些本質(zhì)的差別,但是在一些簡(jiǎn)易的 JavaScript 的幫助下,它們都可以同時(shí)適用于同一個(gè)文檔。本文主要著眼于相互沖突的事件模型中的兩個(gè)關(guān)鍵方面:

          • 把一個(gè)事件和 HTML 元素綁定起來的方法。
          • 在事件被觸發(fā)后如何對(duì)之進(jìn)行處理。

          事件綁定的方法

          事件綁定是指構(gòu)造一個(gè)響應(yīng)系統(tǒng)或者用戶動(dòng)作的 HTML 元素的過程。在不同的瀏覽器版本中,有不少于五種事件綁定技術(shù)。下面我們快速地介紹一下這些技術(shù)。

          事件綁定方法I:綁定元素屬性

          最簡(jiǎn)單和向后兼容性最好的事件綁定方法是把事件綁定到元素標(biāo)識(shí)的屬性。事件屬性名稱由事件類型外加一個(gè)“on”前綴構(gòu)成。盡管HTML屬性并不是大小寫敏感的,人們還是定義了一個(gè)規(guī)則,規(guī)定事件類型的每一個(gè)“詞”的首字母大寫,比如 onClickonMouseOver。這些屬性也被稱為事件處理器,因?yàn)樗鼈冎甘玖嗽厝绾巍疤幚怼碧囟ǖ氖录愋汀?/p>

          正確的事件處理器屬性的值在形式上是被引號(hào)包含的 JavaScript 語句。最常見的值是一條調(diào)用某個(gè)腳本函數(shù)的語句,而被調(diào)用的函數(shù)在位于文檔前部的 <SCRIPT> 標(biāo)識(shí)中定義--該標(biāo)識(shí)通常位于 <HEAD> 部分。舉例來說,下面的函數(shù):

          				function myFunc() {
              // script statements here
          }
          		

          可以被定義為一個(gè)按鍵控件的事件處理器,按鍵的定義如下:

          				<INPUT TYPE="button" NAME="myButton" VALUE="Click Here" 
          onClick="myFunc()">
          		

          把事件綁定到元素屬性上有一個(gè)優(yōu)點(diǎn),即可以支持開發(fā)者把參數(shù)傳遞給事件處理器函數(shù)。接收事件的元素的引用則由一個(gè)特殊的參數(shù)值--this 關(guān)鍵字來傳遞。下面的代碼演示一個(gè)函數(shù)如何借助傳入?yún)?shù),把任意數(shù)目的文本框的內(nèi)容轉(zhuǎn)化為大寫:

          				<SCRIPT LANGUAGE="JavaScript">
          function convertToUpper(textbox) {
              textbox.value = textbox.value.toUpperCase();
          }
          </SCRIPT>
          ...
          <FORM ....>
          <INPUT TYPE="text" NAME="first_name" onChange="convertToUpper(this)"&gt
          <INPUT TYPE="text" NAME="last_name" onChange="convertToUpper(this)"&gt
          ...
          </FORM>
          		

          事件綁定方法II:綁定對(duì)象屬性

          對(duì)于 NN3+ 和 IE4+ 這兩類瀏覽器,腳本編程人員可以以腳本語句的方式把事件綁定到對(duì)象上,而不是綁定到元素標(biāo)識(shí)的屬性上。每一個(gè)負(fù)責(zé)事件響應(yīng)的元素對(duì)象都為自己能夠識(shí)別的事件設(shè)置了相應(yīng)的屬性。對(duì)象屬性名稱是元素標(biāo)識(shí)屬性的小寫形式,比如 onmouseover。NN4 還接受 interCap(即首字小寫,之后的每一個(gè)詞的首字大寫)版本的屬性名,但是考慮到跨瀏覽器的兼容性,所有字母都是小寫的名稱會(huì)更安全一些。

          當(dāng)您把一個(gè)函數(shù)的引用賦值給一個(gè)事件屬性的時(shí)候,就發(fā)生了綁定。函數(shù)的引用是指函數(shù)的名稱,但是不帶函數(shù)定義中的括號(hào)。因此,如果要為一個(gè)名為 myButton 的按鍵的點(diǎn)擊事件(click)進(jìn)行綁定,使之激活一個(gè)定義為 myFunc() 的函數(shù),則其賦值語句如下所示:

          				document.forms[0].myButton.onclick = myFunc;
          		

          您應(yīng)該注意一點(diǎn):在事件觸發(fā)的時(shí)候,沒有辦法向事件函數(shù)傳遞參數(shù)。本文在稍候?qū)κ录幚磉^程的討論中還會(huì)回顧這個(gè)問題。

          事件綁定方法III: 綁定 IE4+<SCRIPT FOR> 標(biāo)識(shí)

          在 IE4+ 中,Microsoft 對(duì) <SCRIPT> 標(biāo)識(shí)實(shí)現(xiàn)了自己的擴(kuò)展,可以將它包含的腳本語句和某個(gè)元素的一個(gè)事件類型進(jìn)行綁定。支持這個(gè)綁定的標(biāo)識(shí)屬性(還沒有被 W3C 批準(zhǔn)為 HTML 的一部分)是 FOREVENT

          FOR 屬性的值必須是您為元素的 ID 屬性分配的唯一標(biāo)識(shí)符。然后,您必須把事件的名稱(onmouseover,onclick,等等)分配給 EVENT 屬性。在上面的按鍵實(shí)例的基礎(chǔ)上,我們必須對(duì)按鍵標(biāo)識(shí)進(jìn)行修改,使之包含一個(gè) ID 屬性:

          				<INPUT TYPE="button" NAME="myButton" ID="button1" VALUE="Click Here">
          		

          腳本語句并不在函數(shù)中,而是在 <SCRIPT> 標(biāo)識(shí)中,如下所示:

          				<SCRIPT FOR="button1" EVENT="onclick">
          // script statements here
          </SCRIPT>
          		

          當(dāng)然,標(biāo)識(shí)中的語句可以調(diào)用頁面上其它地方定義的任何函數(shù)(或者從.js文件中導(dǎo)入的函數(shù))。然而,這種綁定方式意味著您必須為每一個(gè)元素和每一個(gè)事件創(chuàng)建一個(gè) <SCRIPT FOR> 標(biāo)識(shí)。

          您還必須小心,只能把這種綁定方法部署在僅供 IE4+ 瀏覽器瀏覽的頁面。其它任何支持腳本編程而又沒有實(shí)現(xiàn)這個(gè)特殊的 <SCRIPT> 標(biāo)識(shí)的瀏覽器(包括 IE3),都將把它作為常規(guī)的 <SCRIPT> 標(biāo)識(shí)來處理,并試圖在頁面裝載的時(shí)候執(zhí)行這些腳本語句--這不可避免地引起腳本錯(cuò)誤。

          事件綁定方法IV:使用 IE5/Windows 的 attachEvent() 方法

          早在 W3C DOM 工作組磨礪出標(biāo)準(zhǔn)的事件模型之前,attachEvent() 方法已經(jīng)被實(shí)現(xiàn)了,并且可被用于 Windows 版的 IE5 或更新版本的瀏覽器上的每一個(gè) HTML 元素。

          attachEvent() 方法的用法如下所示:

          				
          						elemObject.attachEvent("eventName", functionReference);
          		

          eventName 參數(shù)的值是表示事件名稱的字符串,比如 onmousedownfunctionReference 參數(shù)是一個(gè)不帶括號(hào)的函數(shù)引用,和早些時(shí)候描述的事件屬性方法中一樣。因此對(duì)于上面例子的按鍵對(duì)象,可以通過如下的腳本語句把函數(shù)綁定到按鍵的 click 事件:

          				document.getElementById("button1").attachEvent("onclick", myFunc);
          		

          由于 attachEvent() 方法必須嚴(yán)格工作在 IE5+/Windows 的環(huán)境中,所以您既可以使用 W3C DOM 的元素引用方式(如上文所示),也可以使用 IE4+ 的引用方式:

          				document.all.button1.attachEvent("onclick", myFunc);
          		

          這個(gè)方法有一個(gè)值得注意的地方:您不能在元素被載入瀏覽器之前執(zhí)行這個(gè)語句。該對(duì)象的引用在相應(yīng)的 HTML 按鍵元素被瀏覽器創(chuàng)建之前,都是無效的。因此,要讓這樣的綁定語句或者在頁面的底部運(yùn)行,或者在 BODY 元素的 onLoad 事件處理器調(diào)用的函數(shù)中運(yùn)行。

          事件綁定方法V:使用 W3C DOM 的 addEventListener() 方法

          Safari 使用的是 W3C DOM 級(jí)別2定義的事件綁定機(jī)制,這個(gè)機(jī)制和 IE5/Windows 的 attachEvent() 方法很類似,但是有自己的語法。W3C DOM 規(guī)范為 DOM 層次中的每一個(gè)結(jié)點(diǎn)都定義了一個(gè) addEventListener() 方法。HTML 元素是 DOM 結(jié)點(diǎn)中的一類,在一對(duì)元素標(biāo)識(shí)內(nèi)部的文本結(jié)點(diǎn)也是一個(gè)結(jié)點(diǎn),也能夠接收事件。這一點(diǎn)在 NN6 事件處理過程中經(jīng)常得到體現(xiàn),在本文的后面部分您將會(huì)看到。

          addEventListener() 方法的語法如下所示:

          				
          						nodeReference.addEventListener("eventType", listenerReference, captureFlag);
          		

          用 W3C DOM 規(guī)范中的行話來說,addEventListener() 方法為指定的結(jié)點(diǎn)注冊(cè)了一個(gè)事件,表示該結(jié)點(diǎn)希望處理相應(yīng)的事件。這個(gè)方法的第一個(gè)參數(shù)是一個(gè)聲明事件類型的字符串(不帶"on"前綴),比如 clickmousedown,和 keypressaddEventListener() 方法的第二個(gè)參數(shù)可以和早些時(shí)候描述過的函數(shù)引用同樣對(duì)待。第三個(gè)參數(shù)則是一個(gè) Boolean 值,指明該結(jié)點(diǎn)是否以DOM中所謂的捕捉模式來偵聽事件。事件的捕捉和派發(fā)---綜合起來稱為事件的傳播--最后由另一篇文章來描述。對(duì)于一個(gè)典型的事件偵聽器來說,第三個(gè)參數(shù)應(yīng)該為 false(假)

          那種綁定方法最好?

          如果您足夠幸運(yùn),只需要為某一個(gè)操作系統(tǒng)上特定版本的瀏覽器創(chuàng)建應(yīng)用程序,則可以為選定的瀏覽器選擇最現(xiàn)代的綁定方式。但是對(duì)于跨瀏覽器的網(wǎng)站作者來說,選擇綁定方法則需要面對(duì)實(shí)質(zhì)性的挑戰(zhàn)。

          如果您只計(jì)劃支持 IE5/Mac,則可以不考慮 attachEvent()addEventListener() 方法,因?yàn)?IE5/Mac 對(duì)這兩種方法都不支持。這種情況下,比較實(shí)際的選擇有兩種,要么綁定標(biāo)識(shí)屬性,要么綁定對(duì)象屬性。這時(shí)就需要費(fèi)心思了。

          一方面,W3C DOM Level 2 承認(rèn)基于標(biāo)識(shí)屬性的方法,并將它推薦為 addEventListener() 方法的可接受代替方法。為了和數(shù)以百萬計(jì)的腳本相兼容,所有支持腳本編程的瀏覽器都支持基于標(biāo)識(shí)屬性的事件綁定方法。一些自動(dòng)化的頁面制作工具,比如 DreamWeaver,也把事件處理器的屬性嵌入到 HTML 標(biāo)識(shí)中。

          但是另一方面,在元素標(biāo)識(shí)文件中嵌入面向腳本的信息,又不能將內(nèi)容從風(fēng)格及行為中分離開來,這和當(dāng)前的流行趨勢(shì)相違背。把事件綁定到對(duì)象屬性上的方法聽起來方向是對(duì)的,但是在 W3C 關(guān)于 HTML,XHTML,或者 DOM 的標(biāo)準(zhǔn)中,并沒有對(duì)事件屬性提供“官方”的支持。盡管如此,在實(shí)際生活中,除了第一代支持腳本編程的瀏覽器之外,其它瀏覽器都支持這種方法。

          一個(gè)純標(biāo)準(zhǔn)論者會(huì)認(rèn)為上述的兩種方法都有缺點(diǎn),但是對(duì)于講究實(shí)際的開發(fā)者來說,即使考慮到未來主流瀏覽器的兼容性,這兩種方法都是“安全”的。

          事件的信息礦:事件對(duì)象

          所有這三種事件模型的核心都是一個(gè)事件對(duì)象--它是一個(gè)抽象的實(shí)體,其屬性中包含很多對(duì)事件處理函數(shù)具有潛在價(jià)值的信息。從本文早些時(shí)候?qū)κ录壎夹g(shù)的討論中,您可能可以推斷出事件對(duì)象對(duì)腳本之所以至關(guān)重要,原因之一是除了基于標(biāo)識(shí)屬性的綁定方法以外,其它綁定方法都不支持將參數(shù)傳遞到事件處理函數(shù)中。

          事件對(duì)象通過提供足夠的“掛鉤”,使事件處理函數(shù)可以讀取事件的特征,從而填補(bǔ)了這個(gè)縫隙。因此,事件處理函數(shù)可以得到接收事件的元素的引用,以及其它一些有用的信息,比如鼠標(biāo)動(dòng)作的坐標(biāo),鼠標(biāo)使用的按鍵,鍵盤上被按壓的鍵,以及在事件發(fā)生的過程中是否有修飾鍵被按下(比如檢測(cè) Shift-click 事件)。

          訪問事件對(duì)象

          雖然事件對(duì)象的精確構(gòu)成因?yàn)楸疚挠懻摰娜N DOM(NN4,IE4+,以及 W3C/Safari)的不同而有所變化,但是,一個(gè)事件處理函數(shù)只能通過以下兩種方式之一來訪問事件對(duì)象:NN 方式和 IE 方式。W3C/Safari DOM 事件對(duì)象公布給腳本的接口方式和 NN4 的事件對(duì)象一樣;而 IE4+ 則有自己的方法。

          IE4+ 的事件對(duì)象更加易于描述,因此我們首先對(duì)它進(jìn)行討論。簡(jiǎn)單地說,事件對(duì)象是 window 對(duì)象的一個(gè)屬性。這意味著在所有的實(shí)例中只有一個(gè)事件對(duì)象。舉例來說,在鍵盤上簡(jiǎn)單地按壓和松開一個(gè)按鍵,會(huì)產(chǎn)生三個(gè)事件:onKeyDownonKeyPress,和 onKeyUp(事件的發(fā)生順序和這里的列舉順序相同)。如果 onKeyDown事 件激活的函數(shù)花費(fèi)很長(zhǎng)的時(shí)間進(jìn)行處理,則瀏覽器就會(huì)把其它兩個(gè)事件保持在隊(duì)列中,直到 onMouseDown 事件處理完成為止。

          而對(duì)于 NN4 和 W3C DOM 來說,事件對(duì)象看起來就更加抽象一些。除了基于標(biāo)識(shí)屬性風(fēng)格的綁定方法之外,其它綁定方法都是把事件對(duì)象自動(dòng)傳遞給與事件相綁定的函數(shù)。傳遞給函數(shù)的是一個(gè)單一的參數(shù)。開發(fā)者需要在函數(shù)中定義一個(gè)參數(shù)變量,來“接收”該參數(shù)的值。為了避免和IE中的 window.event 對(duì)象互相沖突,請(qǐng)不要把參數(shù)命名為 event。舉例來說,把它命名為 evt 就相當(dāng)好,相應(yīng)的事件函數(shù)的定義大致如下:

          				function myFunc(evt) {
              // script statements here
          }
          		

          然而,如果您使用的是基于標(biāo)識(shí)屬性的事件綁定技術(shù),就必須顯式地把事件作為一個(gè)參數(shù)傳遞到您調(diào)用的函數(shù)。為了完成事件的傳遞,需要把 event 這個(gè)關(guān)鍵字作為參數(shù)進(jìn)行傳遞:

          				onClick = "myFunc(event)"
          		

          外部傳入的參數(shù)是您的事件處理函數(shù)和 NN 的事件對(duì)象之間的唯一聯(lián)系紐帶。如果在主事件處理函數(shù)內(nèi)部調(diào)用的其它函數(shù)需要該對(duì)象或者該對(duì)象的屬性值,則您可以把該對(duì)象或其屬性值作為參數(shù)中繼給這些函數(shù)。

          如果您想知道 IE 是否把事件的引用保存在 window.event 屬性中,那答案是“是”。使用這個(gè)語法交集是相當(dāng)安全的,因?yàn)樵?NN 和 IE 這兩個(gè)瀏覽器,被傳遞到事件處理函數(shù)的事件對(duì)象都有您所期望的當(dāng)前事件的屬性值。

          兼容兩種事件對(duì)象引用

          設(shè)想在處理事件時(shí),我們需要在一個(gè)事件函數(shù)中考察一個(gè)或者多個(gè)事件屬性。這是一個(gè)簡(jiǎn)單的技術(shù),可以使事件處理函數(shù)和作為參數(shù)傳入的事件對(duì)象協(xié)同工作,或者從 window.event 屬性中讀取信息。而且,這個(gè)技術(shù)不必處理不同的瀏覽器版本之間的細(xì)微差別。

          在開始的時(shí)候,需要在您的事件處理函數(shù)中定義一個(gè)參數(shù)變量,準(zhǔn)備接收可能傳入的事件對(duì)象。然后,通過簡(jiǎn)單的條件表達(dá)式把瀏覽器的事件對(duì)象賦值給上述的參數(shù)變量:

          				function myFunc(evt) {
              evt = (evt) ? evt : ((window.event) ? window.event : "")
              // process event here
          }
          		

          如果事件對(duì)象真的以參數(shù)的形式傳進(jìn)來了,則在函數(shù)內(nèi)部,事件對(duì)象就被保留在 evt 這個(gè)局部變量中。如果這個(gè)參數(shù)是 null,而且瀏覽器的 window 對(duì)象包含有一個(gè) event 屬性,則 window.event 對(duì)象就會(huì)把自己賦值給 evt 變量。

          然而,為了完成這個(gè)工作,還應(yīng)該再包含一層或者多層條件控制,以便優(yōu)雅地適應(yīng)那些在事件模型中沒有定義事件對(duì)象的的早期瀏覽器:

          				function myFunc(evt) {
              evt = (evt) ? evt : ((window.event) ? window.event : "")
              if (evt) {
                  // process event here
              }
          }
          		

          為了把同樣的方式應(yīng)用到所有事件處理函數(shù)的構(gòu)建中,您可以定義一個(gè)函數(shù)來兼容兩種事件,即由綁定的標(biāo)識(shí)屬性顯式傳入的事件對(duì)象,以及由綁定的事件屬性隱式傳入的事件對(duì)象。這樣即使您在開發(fā)過程中改變了事件綁定的風(fēng)格,這個(gè)函數(shù)也不必改變。

          瑞典自助餐式地選擇事件對(duì)象

          然而,建立一個(gè)指向事件對(duì)象的引用只是戰(zhàn)斗的一部分。來自不同事件模型的每一個(gè)事件對(duì)象都擁有自己的一套屬性,以容納事件的細(xì)節(jié)。下面的表格列出了最常用的屬性,以及這些屬性在上述三種事件對(duì)象類型中的名稱。

          表格 1. 流行的事件對(duì)象屬性

          描述 NN4 IE4+ W3C/Safari
          Event target target srcElement target
          Event type type type type
          X coordinate on page pageX * pageX
          Y coordinate on page pageY * pageY
          Mouse button which button button
          Keyboard key which keyCode keyCode

          標(biāo)注*的屬性值可以通過對(duì) event.clientX + document.body.scrollTop 或者 event.clientY + document.body.scrollTop 進(jìn)行求值來得到。

          Macintosh 版本的IE5在通常情況下都遵循 IE4+ 的事件對(duì)象模型,但是有一個(gè)例外,即 IE5/Mac 的事件對(duì)象既定義了 srcElement 屬性,也定義了 target 屬性,這兩個(gè)屬性都指向接收事件的元素。

          需要抽象的最重要的事件對(duì)象屬性可能得算指向接收事件的 HTML 元素的引用。NN4 和 W3C 的事件對(duì)象采用相同的屬性名(target),而 IE4+ 的事件對(duì)象則使用 srcElement 屬性。這時(shí)候,對(duì)象檢測(cè)技術(shù)(而不是費(fèi)力勞神而又具有危險(xiǎn)傾向的瀏覽器版本識(shí)別方法)再次拯救了我們。對(duì)于那些非文本容器的元素,一個(gè)簡(jiǎn)單的條件表達(dá)式就可以輕松處理腳本語法上的差別:

          				var elem = (evt.target) ? evt.target : evt.srcElement
          		

          從現(xiàn)在開始,您的腳本就可以讀寫任何瀏覽器對(duì)象模型公布出來的元素對(duì)象屬性了。

          W3C DOM結(jié)點(diǎn)的事件目標(biāo)

          W3C DOM 的結(jié)點(diǎn)架構(gòu)使得文檔中的每一個(gè)結(jié)點(diǎn)都可以接收事件。在支持這一架構(gòu)的瀏覽器中,發(fā)生在嵌套文本頂上的事件并不調(diào)用分配給文本容器的事件處理器,相應(yīng)的文本結(jié)點(diǎn)才是該事件的目標(biāo)結(jié)點(diǎn)。考慮如下場(chǎng)景:

          事件實(shí)例,當(dāng)鼠標(biāo)的指針在一個(gè) SPAN 元素包含的文本頂上滾動(dòng)時(shí),該文本就會(huì)被高亮顯示。 事件綁定的過程通過對(duì)象屬性在 init() 函數(shù)中進(jìn)行。從表面上看,當(dāng)用戶在 SPAN 元素頂上滾動(dòng)鼠標(biāo)時(shí),onMouseOver 事件動(dòng)作函數(shù)就為該元素指派一個(gè)與風(fēng)格表單規(guī)則相關(guān)聯(lián)的類名(highlight),該風(fēng)格規(guī)則把文本的顯示風(fēng)格定義為粗體,黃色背景;而在 onMouseOut 函數(shù)中,則把風(fēng)格恢復(fù)為原始的版本(類 normal)。請(qǐng)注意一個(gè) toggleHighlight() 函數(shù)是如何在事件對(duì)象的 type 屬性的幫助下,執(zhí)行兩個(gè)動(dòng)作的(該屬性在所有事件模型對(duì)象中的名稱是相同的)。請(qǐng)試一下這個(gè)事件實(shí)例

          但是如果您把例子裝載到 NN6,則鼠標(biāo)事件的真正目標(biāo)就是 SPAN 元素中的文本結(jié)點(diǎn)了。本文并不討論事件的傳播機(jī)制,但是請(qǐng)相信,W3C DOM 事件模型的缺省行為會(huì)使事件沿著結(jié)點(diǎn)的包含層次向上傳播(和 IE4+ 中事件通過元素容器向上傳播的機(jī)制很類似)。因此,在這個(gè)事件實(shí)例中。鼠標(biāo)事件會(huì)從其真正的目標(biāo)向上傳遞到文本結(jié)點(diǎn)的容器(也就是 SPAN 元素)。這些事件觸發(fā)了 SPAN 元素中相應(yīng)的事件處理器。

          雖然事件處理器屬于 SPAN 元素,事件對(duì)象還是保留文本對(duì)象的引用,并將它作為事件的原始目標(biāo)。然而,只有對(duì)文本結(jié)點(diǎn)的容器進(jìn)行動(dòng)作,才能修改它的風(fēng)格。為了實(shí)現(xiàn) toggleHighlight() 函數(shù)的等價(jià)操作,使之可以修改SPAN容器的 className 屬性,該函數(shù)需要派生出一個(gè)指向文本結(jié)點(diǎn)容器的引用。

          一個(gè)策略是使用 W3C DOM 事件對(duì)象的 currentTarget 屬性,該屬性返回一個(gè)處理事件的結(jié)點(diǎn)的引用。腳本中的決策樹需要考慮這個(gè)屬性,增加代碼之后的 toggleHighlight() 函數(shù)如下所示:

          				function toggleHighlight(evt) {
              evt = (evt) ? evt : ((window.event) ? window.event : "")
              if (evt) {
                  var elem
                  if (evt.target) {
                      if (evt.currentTarget && (evt.currentTarget != evt.target)) {
                          elem = evt.currentTarget
                      } else {
                          elem = evt.target
                      } 
                  } else {
                      elem = evt.srcElement
                  }
                  elem.className = (evt.type == "mouseover") ? "highlight" : "normal"
              }
          }
          		

          另一個(gè)可選的方法是考察由 target 屬性返回的對(duì)象的 ronodeType 屬性。一個(gè)能夠把事件定向給文本結(jié)點(diǎn)的瀏覽器,也可以把一個(gè)文本結(jié)點(diǎn)的 nodeType 屬性值報(bào)告為3,而不是報(bào)告為元素結(jié)點(diǎn)的類型(其值為1)。如果事件的目標(biāo)是一個(gè)文本結(jié)點(diǎn),則腳本程序就可以通過該文本結(jié)點(diǎn)的 parentNode 屬性來得到其上級(jí)元素結(jié)點(diǎn)的引用。這種方法的決策樹在某種程度上得到更多的改進(jìn):

          				function toggleHighlight(evt) {
              evt = (evt) ? evt : ((window.event) ? window.event : "")
              if (evt) {
                  var elem
                  if (evt.target) {
                      elem = (evt.target.nodeType == 3) ? evt.target.parentNode : evt.target
                  } else {
                      elem = evt.srcElement
                  }
                  elem.className = (evt.type == "mouseover") ? "highlight" : "normal"
              }
          }
          		

          如果您正在用遵循 W3 的瀏覽器閱讀本文,則請(qǐng)嘗試這個(gè)修改過的版本,看看鼠標(biāo)滾動(dòng)時(shí)的風(fēng)格變化。

          這個(gè)頁面使用了嵌入到事件實(shí)例中的最新版本的 toggleHighlight() 函數(shù),展示了如何使用 JavaScript 為那些能夠顯示期望效果的瀏覽器增加額外的價(jià)值,同時(shí)也可以那些基本的內(nèi)容提供給仍然使用著較老版本或者不支持腳本編程的瀏覽器的用戶,只不過在模式上不那么動(dòng)人和便于交互。

          一個(gè)事件處理函數(shù)的模板

          并不是每個(gè)事件處理函數(shù)都處理頁面元素對(duì)象中同樣的屬性或者行為,但是,從上文的討論可以派生出來的一個(gè)模板,您可以在這個(gè)模板的幫助下開始編碼。模板如下:

          				function functionName(evt) {
              evt = (evt) ? evt : ((window.event) ? window.event : "")
              if (evt) {
                  var elem
                  if (evt.target) {
                      elem = (evt.target.nodeType == 3) ? evt.target.parentNode : evt.target
                  } else {
                      elem = evt.srcElement
                  }
                  if (elem) {
                      // process event here
                  }
              }
          }
          		

          請(qǐng)把第一行的函數(shù)名替換為您希望的函數(shù)名,并在注視指示的地方開始書寫具體事件的代碼。這個(gè)格式應(yīng)該可以為您提供一個(gè)起點(diǎn),適合于您采用的任何跨瀏覽器的事件綁定風(fēng)格。如果您需要在一個(gè)頁面中多次使用這個(gè)格式,則可以進(jìn)一步精簡(jiǎn)代碼,即把讀取目標(biāo)的代碼抽象成一個(gè)可重用的工具函數(shù),然后在每一個(gè)事件處理函數(shù)中進(jìn)行調(diào)用:

          				// shared function
          function getTargetElement(evt) {
              var elem
              if (evt.target) {
                  elem = (evt.target.nodeType == 3) ? evt.target.parentNode : evt.target
              } else {
                  elem = evt.srcElement
              }
              return elem
          
          }
          
          function functionName(evt) {
              evt = (evt) ? evt : ((window.event) ? window.event : "")
              if (evt) {
                  var elem = getTargetElement(evt)
                  if (elem) {
                      // process event here
                  }
              }
          }
          		

          有了這類框架,您現(xiàn)在應(yīng)該可以把更多的注意力集中在各個(gè)事件處理函數(shù)要求的具體動(dòng)作中了。

          查看實(shí)例:

          下載腳本

          posted on 2006-05-31 09:36 jackstudio 閱讀(505) 評(píng)論(0)  編輯  收藏 所屬分類: javascript

          只有注冊(cè)用戶登錄后才能發(fā)表評(píng)論。


          網(wǎng)站導(dǎo)航:
           
          主站蜘蛛池模板: 汝州市| 阜新| 故城县| 句容市| 郎溪县| 云和县| 阳江市| 珲春市| 廉江市| 阿克苏市| 大连市| 阜南县| 永兴县| 合水县| 桑日县| 吉隆县| 达州市| 罗田县| 阳江市| 商城县| 南通市| 陇南市| 五指山市| 措美县| 义乌市| 墨脱县| 龙游县| 甘谷县| 九台市| 都匀市| 鹤岗市| 古丈县| 融水| 海城市| 鲁山县| 浠水县| 南宁市| 温宿县| 碌曲县| 铜川市| 庆阳市|