js事件——Events

沒有共產黨就沒有新中國,沒有 events 就沒有 scripts。每個包含 JavaScript 的頁面中: 幾乎所有的腳本都是由 event 觸發的。原因很簡單。 JavaScript 可以增加交互性: user 做一些操作,頁面給出響應。Events 是所有 JavaScript 應用的小心臟。本文介紹了事件處理機制,相關問題以及如何寫出跨瀏覽器的 scripts。同時也展示了幾個帶有事件處理細節的頁面。

因此JavaScript 檢測用戶的操作,以便知道何時做出反應,反應時執行哪個 functions 。

當用戶做出某操作就會觸發一個 event 。也有一些  events 不是由用戶直接觸發: 例如 load event 是頁面加載時觸發的。

JavaScript 可以檢測一些 events。從 Netscape 2 開始就可以把事件處理程序( event handler)附加到某個HTML 元素。 事件處理程序會等候某個 event (例如 鏈接上的 click 事件 )發生。這時候就會執行你定義好的JavaScript 代碼來處理事件 。

用戶操作會產生一個 event。當 script 對 event做出響應,這就是所謂的交互。

事件處理的歷史

假如沒有事件處理機制,在頁面中添加 JavaScript 就毫無意義。好的腳本可以對用戶操作做出響應。因此網景發佈第二版支持JavaScript的瀏覽器時,它也支持事件處理機制。

Netscape 模型

Netscape 2 只支持一些 events。Mouseover 和 mouseout 很快風靡,因爲可以通過onMouseOver 改變  images ,通過onMouseOut 把它們變回去。在那個時候是很神奇的。也可以看到用戶 submit  或 reset 表單,因此實現了客戶端表單驗證( form validation)。瀏覽器也可以檢測表單獲得焦點、失去焦點、頁面加載完成、開始上傳等。儘管現在看來很稀鬆平常,但是在那個年代,這可是Web頁面革命性的進展。真正的交互成爲了可能,因爲你可以對用戶操作做出響應。

最古老的事件處理就下面一樣:

<a href="somewhere.html" οnclick="alert('I\'ve been clicked!')">

這種最古老的事件處理機制實際上是由Netscape 定義的標準。如果想要JavaScript工作,其他的瀏覽器包括IE都得遵從Netscape 2和3的處理事件的標準。因此這些最古老的事件和事件處理程序在任何JavaScript瀏覽器中都能很好地運行。

現代事件模型

然而,自從引進這些簡單的事件處理器後很多東西都發生了變化。首先事件數量增加,同時,事件註冊機制也發生了變化。現在可以完全由JavaScript來設置。不再需要大量的附着於代碼之上,你可以寫一些很簡單的代碼來設置所有的事件處理程序。

第4版的瀏覽器還提供了更多的關於事件本身的信息。光標在哪兒(光標在撒錢)事件何時觸發?有沒有鍵被按? 如果該界面元素存在父子元素,而且父子元素也定義了同樣的事件,這個時候事件該如何處理呢,事件在父子元素之間是如何傳遞的呢,誰會先接收到這個事件,又是誰先處理呢?不同的瀏覽器其處理機制也不盡相同。

在網景和微軟鬥爭的年代,兩個公司選擇了完全不同的事件模型。W3C非常理智的處理了這種差異,在兩者之間採取了中和的方法 DOM Event specification。除了一個嚴重漏洞( serious flaw), W3C的模型, 添加了很多新功能並解決了舊模型的很多問題。

三個模型意味着事件處理機制在不同的瀏覽器中可能有所不同。

瀏覽器兼容性問題

 就像 DHTML,W3C DOM 或其他的高級腳本技術一樣,我們必須在瀏覽器中小心翼翼地執行代碼。 在 Explorer 中調用 stopPropagation() 或者在 Netscape調用 srcElement 將會導致嚴重的錯誤甚至導致腳本不可用。因此在使用之前,我們必須確保瀏覽器支持該方法或該屬性( the methods or properties) 。

如下一個簡單的代碼分支

if (Netscape) {
	use Netscape model
}
else if (Explorer) {
	use Microsoft model
}

只是一個近似的解決方案,因爲它忽略了非主流的瀏覽器。現在的解決方案可以處理大量的 modern event handling,除非你的腳本機智地設定非主流瀏覽器不允許執行代碼,因爲它們不是 Netscape 或 Explorer。

所有其他非主流的瀏覽器都必須做出決定站在哪一隊:支持哪一種模型。Konqueror/Safari, 選擇了嚴格的標準並支持 W3C model。Opera and iCab 則比較謹慎,支持舊的 Netscape model 和 Microsoft model中的大部分。

但非主流的瀏覽器可能支持的是 Microsoft 標準,但實際上其事件屬性既有 W3C 的也有 old Netscape model的。

不要使用瀏覽器檢測

首先,千萬不用使用 browser detect。這是最快的作死方法。任何代碼如果使用navigator.userAgent事件模型檢測簡直沒用還沒用應該直接拉出去彈JJ。

其次,不要將 DHTML 對象檢測(object detection  )與事件對象檢測混爲一談。當書寫DHTML 時我們通常這樣檢測是否支持DOM: if (document.all) is supported. 如果是醬紫,使用 Microsoft allcontainer 的腳本可以正常執行。

但 DHTML和事件處理程序有不同的瀏覽器兼容模式。例如: Opera 6 支持部分 W3C DOM 但不支持 W3C event model。因此在Opera中。所以代碼使用  if (document.layers) 或者其他的事件模型檢測都是不正確的。

正確的提問

然後我們應該做些什麼? 事件屬性( event properties)引起嚴重的問題。如果我們使用大量特定對象檢測,可以解決99%的瀏覽器的不兼容問題。只有鼠標位置( mouse position)非常的麻煩,其他的都比較簡單了。

此外,最好是不去在意三個事件模型。相反,我們必須理解四個事件註冊模型,兩個事件訪問模型和兩個事件的命令。
事件處理和瀏覽器兼容性,參見事件兼容性表( event compatibility tables)。

貌似很複雜,其實so easy。實際上,當我認識到要對不同事件模型單獨處理之後,我纔開始真正理解事件處理。 這都是關於如何提出正確的問題的。別這麼問“如何寫一個事件來處理腳本?”  這是個問題,但很難給出答案,你應該問得再具體一點,別人纔好給出答案:

  • “都有哪些事件?”
    很多,當然在某些瀏覽器中,一些事件無法生效。
  • “如何給一個HTML 元素註冊事件處理程序?
    註冊事件處理器有四種模型: 內斂模型( inline), 傳統模型(traditional), W3C模型和微軟模型(W3C and Microsoft)。第一種方法使用與所有瀏覽器,完全沒有問題。
  • “如何阻止事件的默認行爲?”
    從事件處理腳本中 return false , 默認的動作就會被阻止。該技術標準是由 Netscape 2 定義的,現在依然有效。
  • “若要獲取更多事件相關的屬性,該怎麼做?”
    有兩種方法:W3C 或 Netscape and Microsoft。爲了解決這個問題你還需要這樣一行代碼
  • “接下來改如何讀取它的這些屬性呢?”
    要讀取這些屬性存在兼容性問題,這些問題在事件屬性這篇文章中詳細說明了。要解決兼容性問題還需要參考事件屬性兼容性表 和進行一些嚴格的對象檢測。
  • “元素存在父元素,而且父元素也定義了同樣的事件,這個時候事件該如何處理呢,事件在父子元素之間是如何傳遞的呢,誰會先接收到這個事件,又是誰先處理呢?” — 這個問題很有技術含量
    不同的瀏覽器有不同的方法。有兩個 事件處理順序,事件捕獲(event capturing )和事件冒泡( event bubbling)。在實踐中他們並不是很重要,只有少數情況下會用到,這種情況下我們通常會關心如何把它們關掉。需要兩行代碼。


寫跨瀏覽器的腳本的技巧不是單單使用一個的事件模型,而是問自己上面那些問題。你將會發現需要考慮瀏覽器兼容性的情況:主要是在讀取事件屬性的時候。

首先選擇一種事件註冊模型, 確保所有的瀏覽器都支持該事件,隨後去讀取所需的事件屬性,期間,如果存在兼容性問題的話還需要去解決。這樣你就能瀏覽器兼容性問題各個擊破,也能確保你的代碼能在所有的瀏覽器里正常運行。

繼續

如果你想詳細瞭解事件相關的更加詳細的內容,建議你繼續閱讀 events 這篇文章

編寫事件處理腳本

如何編寫呢?本文我給出了一個概述。

註冊事件處理程序

第一步就是註冊事件處理程序。但必須保證你選擇的事件發生時瀏覽器會執行你的腳本。

註冊事件處理器有四種模型:  內斂模型( inline), 傳統模型(traditional), W3C模型和微軟模型(W3C and Microsoft)。

最好的辦法是使用傳統模式,因爲它是完全兼容的,並給出予很大的自由度和多樣性。 註冊事件處理程序,使用以下方法

element.onclick = doSomething;
if (element.captureEvents) element.captureEvents(Event.CLICK);

現在函數 doSomething() 就被註冊成爲了HTML 元素element 的click 事件處理程序。一旦用戶點擊這個元素, doSomething() 就會被執行。

訪問事件

註冊了事件處理器之後就可以開始書寫實際的腳本了。在通常情況下,你需要訪問事件本身( access the event itself),這樣就可以讀取有關的事件信息。

通常事件處理程序都這樣寫:

function doSomething(e) {
	if (!e) var e = window.event
	// e refers to the event
}

其中 e 指的是所有瀏覽器中可以訪問的事件。

訪問 HTML 元素

有時你也需要訪問事件發生在其上的HTML元素。 有兩種方法:使用this 關鍵字,或者使用 target/srcElement 屬性。

訪問 HTML 元素最穩妥的方法是使用this 。 this  並不能始終指向正確的 HTML 元素,但是結合傳統模型可以良好地工作。

function doSomething(e) {
	if (!e) var e = window.event
	// e refers to the event
	// this refers to the HTML element which currently handles the event
	// target/srcElement refer to the HTML element the event originally took place on
}

target/srcElement 屬性包含了一個引用,指向事件最初發生的 HTML 元素。很有用,但是當事件被捕獲或冒泡( is captured or bubbles up)的時候, target/srcElement 並不會隨之改變:它仍指向事件最初發生的 HTML 元素。 target/srcElement 相關內容詳見 Event properties 頁面,this 關鍵字相關內容詳見 this )

讀取屬性

讀取事件屬性( event properties)是瀏覽器兼容性的軟肋。參考這個表格( event compatibility tables ) 來編寫自己的腳本,讀取想要的信息。

確保儘可能地使用最詳細的對象檢測。 首先檢測每個屬性是否存在,然後讀取它的值。例如:

function doSomething(e) {
	if (!e) var e = window.event
	if (e.keyCode) code = e.keyCode;
	else if (e.which) code = e.which;
}

其中 code 表示瀏覽器中按下的按鍵。

事件順序

最好,你要決定是否想讓事件冒泡( bubble up)。如果不想讓其發生,就阻止事件的傳播:

function doSomething(e) {
	if (!e) var e = window.event
	// handle event
	e.cancelBubble = true;
	if (e.stopPropagation) e.stopPropagation();
}

編寫腳本

現在你可以開始正式寫事件處理的腳本。利用上面那些代碼片段得到的信息,來決定事件發生時到底發生了什麼,以及你的腳本應如何應對。 

注意:時刻保持交互的邏輯思維,不然用戶就麻爪了。


原文:Introduction to Events

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章