建立 JavaScript 事件處理器就是將一個事件、一個物件與 JavaScript 函數相關聯,例如
將 JavaScript 函數指派給 HTML 元素屬性,此法容易編寫,曾十分盛行,且在所有瀏覽器能執行,但是應避免這種做法,因為會汙染 HTML 碼,將 JavaScript 散佈到 HTML 頁面的各處,不但不美觀,還會導致程式人員難以偵錯和管理專案,其次,在 HTML 直接撰寫 JavaScript 程式時,無法應用漸進式改善的概念。
通常都會採用這種方法,因為容易使用,而且在近十年來發佈的每種瀏覽器上都能可靠運作
和任何物件屬性一樣,可以檢查物件屬性值,確認事件監聽器的存在:
而不使用傳統方法的原因有兩個:1.這種方法一次只能監聽一個事件,2.很容易覆蓋現有的事件處理器
同時呼叫兩個監聽器,只會呼叫後者,前者有關的原始事件處理器已經被替換:
W3C(World Wide Web Consortium)提出自己的事件監聽器建立方法,以作為 DOM Level 2 規範的一部份(DOM 規範還定義了事件處理之外的其他瀏覽器行為),此法以兩種方式改善嵌入式和傳統方法:1.賦值在 JavaScript 中完成,並非在 HTML,2.允許相同元素的多個事件處理器。W3C DOM Level 2 方法(嵌入和傳統事件處理被統稱為 DOM Level 0,也就是在事件處理標準未出現前存在的方法)符合邏輯、靈活並易於應用,雖程式碼較傳統多,但幾乎所有瀏覽器都支援,只有 IE9 之前的版本不支援。
在 DOM 事件監聽器上,IE 採用不同方法,所幸 IE9 支援 W3C DOM,從 DOM Level 0 事件監聽器轉移而來的開發人員須轉寫跨平台相容事件處理器。用
綜觀以上,編寫跨瀏覽器風格的
減少大量重複編寫條件敘述,可利用函數的引數替換對應的特定內容:
從風格的角度出發,開發人員往往使用事件和元素的組合來命名事件處理函數,如:
window.onload = init;,這行程式碼表示發生視窗的 load 事件時,應該呼叫 init() 函數,正式來講,可以說已建立或「註冊」一個事件監聽器(Event Listener),init() 函數將作為視窗物件載入事件的事件處理器。參考 MSDN 管理事件監聽程式:https://msdn.microsoft.com/zh-tw/library/dn741342(v=vs.94).aspx
1建立事件監聽器
JavaScript 支援四種不同的事件監聽器建立方式:1. 嵌入式事件處理器
(不建議使用)將 JavaScript 函數指派給 HTML 元素屬性,此法容易編寫,曾十分盛行,且在所有瀏覽器能執行,但是應避免這種做法,因為會汙染 HTML 碼,將 JavaScript 散佈到 HTML 頁面的各處,不但不美觀,還會導致程式人員難以偵錯和管理專案,其次,在 HTML 直接撰寫 JavaScript 程式時,無法應用漸進式改善的概念。
Some Link
後者程式意指,當使用者點擊時,由
doSomething() 函數完成必要的工作,但若無有效的 href 值,在 JavaScript 被停用或不可用時絕對無法處理此連結,對使用者來說,最終結果是網頁似乎已被破壞,因為網頁上的連結沒有任何作用。
2. 傳統事件處理
通常都會採用這種方法,因為容易使用,而且在近十年來發佈的每種瀏覽器上都能可靠運作
注意使用傳統事件指定事件處理器時,使用屬性須為「全小寫字母」,例如:onload、onsubmit
window.onload = init;
window.onload = function(){} //完全適用於匿名函數,不必正式宣告
window.onload = null; //將物件的相關事件屬性設為 null 為刪除事件處理器
和任何物件屬性一樣,可以檢查物件屬性值,確認事件監聽器的存在:
if(typeof window.onload == 'function'){}
而不使用傳統方法的原因有兩個:1.這種方法一次只能監聽一個事件,2.很容易覆蓋現有的事件處理器
同時呼叫兩個監聽器,只會呼叫後者,前者有關的原始事件處理器已經被替換:
document.getElementbyId('theForm').onsubmit = process;
document.getElementbyId('theForm').onsubmit = calculate; //提交表單後,只會呼叫 calculate() 函數
上述問題可以建立一個呼叫兩個函數的事件處理器來解決,但程式碼醜陋,最好不要使用,而且在複雜的專案中有多個 JavaScript 檔案和程式庫,如果 JavaScript 程式使用傳統方法,有可能在其他檔案中已撤銷該事件註冊:
document.getElementbyId('theForm').onsubmit = function(){
process();
calculate();
}
3. W3C 事件處理
W3C(World Wide Web Consortium)提出自己的事件監聽器建立方法,以作為 DOM Level 2 規範的一部份(DOM 規範還定義了事件處理之外的其他瀏覽器行為),此法以兩種方式改善嵌入式和傳統方法:1.賦值在 JavaScript 中完成,並非在 HTML,2.允許相同元素的多個事件處理器。W3C DOM Level 2 方法(嵌入和傳統事件處理被統稱為 DOM Level 0,也就是在事件處理標準未出現前存在的方法)符合邏輯、靈活並易於應用,雖程式碼較傳統多,但幾乎所有瀏覽器都支援,只有 IE9 之前的版本不支援。
- addEventListener( 事件類型[字串] , 事件發生執行[函數] , 表示事件階段[布林值] ):新增事件監聽器
- removeEventListener( 事件類型[字串] , 事件發生執行[函數] , 表示事件階段[布林值] ):刪除事件監聽器
第三個參數,可以始終填入 false 或直接忽略──導致類似假值的 undefined
window.addEventListener('load', init, false); //新增事件監聽器
//多次呼叫 addEventListener() 方法,就能為相同元素的同一事件增加多個事件監聽器
window.addEventListener('load', process, false);
window.addEventListener('load', calculate, false);
window.removeEventListener('load', process, false); //刪除事件監聽器,此時只會執行 calculate() 函數
這裡使用 load 而不是 onload:load 是事件名稱;onload 是 window 物件的對應屬性
當不再需要事件監聽器時應刪除,但是許多程式人員都沒有這麼做,如果試圖刪除不存在的事件監聽器,並不會拋出錯誤。4. IE 瀏覽器事件處理
在 DOM 事件監聽器上,IE 採用不同方法,所幸 IE9 支援 W3C DOM,從 DOM Level 0 事件監聽器轉移而來的開發人員須轉寫跨平台相容事件處理器。用
attachEvent() 和 detachEvent() 代替 addEventListener() 及 removeEventListener(),兩個方法都只有兩個參數。- attachEvent( 事件類型[字串] , 事件發生執行[函數] ):新增事件監聽器
- detachEvent( 事件類型[字串] , 事件發生執行[函數] ):刪除事件監聽器
window.attachEvent('onload', init); //新增事件監聽器
window.detachEvent('onload', init); //刪除事件監聽器
事件名稱與 W3C DOM 的 load 不同,與傳統方法相同
建立事件分配器
綜觀以上,編寫跨瀏覽器風格的
window.onload 程式增加漸進式改善,(為求精確,可對每個條漸檢查屬性 typeof 是否為函數):
if(window.addEventListener){ //W3C
window.addEventListener('load', init, false);
}else if(window.attachEvent){ //olderIE
window.attachEvent('onload', init);
}
減少大量重複編寫條件敘述,可利用函數的引數替換對應的特定內容:
function addEvent(obj, type, fn){
if(obj && obj.addEventListener){ //W3C
obj.addEventListener(type, fn, false);
}else if(obj && obj.attachEvent){ //olderIE
obj.attachEvent('on' + type, fn); //olderIE 寫法要在事件名稱前加上 on 字眼
}
}
addEvent(window, 'load', init); //對於所有瀏覽器,可使用此程式碼呼叫
用 addEventListener() 和 attachEvent() 增加事件並不會覆蓋傳統方法指定的事件處理器
命名事件處理器
從風格的角度出發,開發人員往往使用事件和元素的組合來命名事件處理函數,如:
onSubmitForm()、onFormSubmission()、formSubmissionHandler()、handleFormSubmission()onClickLink()、onLinkClick()、linkClickHandler()、handleClick()onImageMouseOver()、onMouseOverImage()、imageMouseOverHandler()、handleImageMouseOver()