1. 程式人生 > >javascript打造跨瀏覽器事件處理機制:詳解

javascript打造跨瀏覽器事件處理機制:詳解

由於瀏覽器相容的複雜性.打造一個較優的跨瀏覽器事件處理函式.不是件容易的事情.各大類庫也都通過了種種方案去抽象一個龐大的事件機制.

使用類庫可以比較容易的解決相容性問題.但這背後的機理又是如何呢? 下面我們就一點點鋪開來講.

element.addEventListener(eventName, listener, useCapture);
element.removeEventListener(eventName, listener, useCapture);

EventTarget介面通常實現自NodeWindow介面.也就是所謂的DOM元素.

那麼比如window也就可以通過addEventListener來新增監聽.

function loadHandler() {
    console.log(
'the page is loaded!');
}
window.addEventListener(
'load',  loadHandler, false);

移除監聽通過removeEventListener同樣很容易做到, 只要注意移除的控制代碼和新增的控制代碼引用自一個函式就可以了.

window.removeEventListener('load',  loadHandler, false);

如果我們活在完美世界.那麼估計事件函式就此結束了. 

但情況並非如此.由於IE獨樹一幟.通過MSDHTML DOM定義了

attachEventdetachEvent兩個函式取代了addEventListener和removeEventListener.

恰恰函式間又存在著很多的差異性,使整個事件機制變得異常複雜. 

所以我們要做的事情其實就轉移成了.處理IE瀏覽器和w3c標準之間對於事件處理的差異性.

在IE下新增監聽和移除監聽可以這樣寫

function loadHandler() {
    alert(
'the page is loaded!');
}
window.attachEvent(
'onload',  loadHandler); // 新增監聽window.detachEvent(
'onload',  loadHandler); // 移除監聽

從表象看來,我們可以看出IE與w3c的兩處差異:

1. 事件前面多了個"on"字首. 

2. 去除了useCapture第三個引數. 

其實真正的差異遠遠不止這些.等我們後面會繼續分析.那麼對於現在這兩處差異我們很容易就可以抽象出一個公用的函式

複製程式碼 function addListener(element, eventName, handler) {
    
if (element.addEventListener) {
        element.addEventListener(eventName, handler, 
false);
    }
    
elseif (element.attachEvent) {
        element.attachEvent(
'on'+ eventName, handler);
    }
    
else {
        element[
'on'+ eventName] = handler;
    }
}

function removeListener(element, eventName, handler) {
    
if (element.addEventListener) {
        element.removeEventListener(eventName, handler, 
false);
    }
    
elseif (element.detachEvent) {
        element.detachEvent(
'on'+ eventName, handler);
    }
    
else {
        element[
'on'+ eventName] =null;
    }
}
複製程式碼

上面函式有兩處需要注意一下就是:

1. 第一個分支最好先測定w3c標準. 因為IE也漸漸向標準靠近. 第二個分支監測IE.

2. 第三個分支是留給既不支援(add/remove)EventListener也不支援(attach/detach)Event的瀏覽器.  

效能優化 

對於上面的函式我們是運用"執行時"監測的.也就是每次繫結事件都需要進行分支監測.我們可以將其改為"執行前"就確定相容函式.而不需要每次監測. 

這樣我們就需要用一個DOM元素提前進行探測. 這裡我們選用了document.documentElement. 為什麼不用document.body呢? 因為document.documentElement在document沒有ready的時候就已經存在. 而document.body沒ready前是不存在的.

這樣函式就優化成

複製程式碼 var addListener, removeListener,
    
/* test element */
    docEl 
= document.documentElement;

// addListenerif (docEl.addEventListener) {
    
/* if `addEventListener` exists on test element, define function to use `addEventListener` */
    addListener 
=function (element, eventName, handler) {
        element.addEventListener(eventName, handler, 
false);
    };
}
elseif (docEl.attachEvent) {
    
/* if `attachEvent` exists on test element, define function to use `attachEvent` */
    addListener 
=function (element, eventName, handler) {
        element.attachEvent(
'on'+ eventName, handler);
    };
}
else {
    
/* if neither methods exists on test element, define function to fallback strategy */
    addListener 
=function (element, eventName, handler) {
        element[
'on'+ eventName] = handler;
    };
}

// removeListenerif (docEl.removeEventListener) {
    removeListener 
=function (element, eventName, handler) {
        element.removeEventListener(eventName, handler, 
false);
    };
}
elseif (docEl.detachEvent) {
    removeListener 
=function (element, eventName, handler) {
        element.detachEvent(
'on'+ eventName, handler);
    };
}
else {
    removeListener 
=function (element, eventName, handler) {
        element[
'on'+ eventName] =null;
    };
}
複製程式碼

這樣就避免了每次繫結都需要判斷. 

值得一提的是.上面的程式碼其實也是有兩處硬傷. 除了程式碼量增多外, 還有一點就是使用了硬性編碼推測.上面程式碼我們基本的意思就是斷定.如果document.documentElement具備了add/remove方法.那麼element就一定具備(雖然大多數情況如此).但這顯然是不夠安全.

不安全的檢測 

下面兩個例子說明.在某些情況下這種檢測不是足夠安全的. 

複製程式碼 // In Internet Explorervar xhr =new ActiveXObject('Microsoft.XMLHTTP');
if (xhr.open) { } // Errorvar element = document.createElement('p');
if (element.offsetParent) { } // Error 複製程式碼

如: 在IE7下 typeof xhr.open === 'unknown'. 詳細可參考feature-detection

所以我們提倡的檢測方式是

var isHostMethod =function (object, methodName) {
    
var t =typeof object[methodName];
    
return ((t ==='function'|| t ==='object'&&!!object[methodName]) || t ==='unknown';
};

這樣我們上面的優化函式.再次改進成這樣

複製程式碼 var addListener, docEl = document.documentElement; 
if (isHostMethod(docEl, 'addEventListener')) {
    
/* ... */
}
elseif (isHostMethod(docEl, 'attachEvent')) {
    
/* ... */
}
else {
    
/* ... */
}
複製程式碼

丟失的this指標 

this指標的處理.IE與w3c又出現了差異.在w3c下函式的指標是指向繫結該控制代碼的DOM元素. 而IE下卻總是指向window.

複製程式碼 // IEdocument.body.attachEvent('onclick'function () {
    alert(
this=== window); // true    alert(this=== document.body); // false});

// W3Cdocument.body.addEventListener('onclick'function () {
    alert(
this=== window); // false    alert(this=== document.body); // true}); 複製程式碼

這個問題修正起來也不算麻煩

複製程式碼 if (isHostMethod(docEl, 'addEventListener')) {
    
/* ... */
}
elseif (isHostMethod(docEl, 'attachEvent')) {
    addListener 
=function (element, eventName, handler) {
        element.attachEvent(
'on

相關推薦

javascript打造瀏覽器事件處理機制

由於瀏覽器相容的複雜性.打造一個較優的跨瀏覽器事件處理函式.不是件容易的事情.各大類庫也都通過了種種方案去抽象一個龐大的事件機制. 使用類庫可以比較容易的解決相容性問題.但這背後的機理又是如何呢? 下面我們就一點點鋪開來講. element.add

【js事件】js事件封裝函式,js瀏覽器事件處理機制

一、事件流 事件流描述的是從頁面中接受事件的順序。 IE的事件流是事件冒泡流,而Netscape的事件流是事件捕獲流 1、事件冒泡 事件冒泡,即事件最開始由最具體的元素(文件中巢狀層次最深的那個節點)接收,然後逐級向上轉播至最不具體的節點(文件)。 2、事件捕獲 事件捕獲的

瀏覽器事件處理程式

var EventUtil = { addHandler: function(element, type, handler){ if (element.addEventListener){ element.addEventListener(type

Android開發知識(七)Android事件處理機制事件分發、傳遞、攔截、處理機制的原理分析(上)

  在我們剛開始學習安卓的時候,總會一開始就接觸到Button,也就是對按鈕進行一個事件監聽的事件,當我們點選螢幕上的按鈕時就可以觸發一個點選事件。那麼,從我們點選螢幕到按鈕觸發事件這個過程,是什麼樣子的呢?本文我們就來談一下關於事件攔截處理機制的基本知識。

Android開發知識(八)Android事件處理機制事件分發、傳遞、攔截、處理機制的原理分析(中)

  在本章節中,我們重點談論一下onTouch、onClick、onLongClick三個方法被回撥的過程。   在上一篇文章中,我們談到關於為View新增一個點選事件SetOnClickListener後,就可以通過回撥onClick方法來實現事件的響應

13.View的事件分發機制——dispatchTouchEvent

 在前面的第二篇文章中,我們提過,View的事件分發是一種委託思想:上層委託下層,父容器委託子元素來處理這個流程。接下來,我們就將深入去學習View的事件分發機制。 1.事件的傳遞流程     事件,在A

Android事件分發機制流程(二)

前言:上一篇我們已經從事件分發執行流程入手,一起來了解並分析了事件分發的經過,大家應該從分析中能對事件分發的有個總體的認識,並且我相信應該也能自己分析出事件會如何執行,其實就那麼點東西,弄明白了就不難了,但是今天我們還是要來看看activity,viewg

事件分發機制及原始碼分析

事件分發機制詳解 MotionEvent 主要分為以下幾個事件型別: ACTION_DOWN 手指開始觸控到螢幕的那一刻響應的是DOWN事件 ACTION_MOVE 接著手指在螢幕上移動響應的是MOVE事件 ACTION_UP 手指從螢幕上鬆開的那一刻響

Android View 事件分發機制原始碼(ViewGroup篇)

前言 我們在學習View的時候,不可避免會遇到事件的分發,而往往遇到的很多滑動衝突的問題都是由於處理事件分發時不恰當所造成的。因此,深入瞭解View事件分發機制的原理,對於我們來說是很有必要的。由於View事件分發機制是一個比較複雜的機制,因此筆者將寫成兩篇文

事件處理機制--瀏覽器流程處理分析

style chan 一件事 cli con open() -h response xhr 事件處理機制--瀏覽器流程處理分析 js的運行是單線程的,單線程即一個時間只能做一件事。瀏覽器的運行是多線程的。 如下三種情況會進入事件隊列(任務隊列)中,但不立即執行:   1.定

這篇文章對於瞭解Javascript事件處理機制非常好,將它全文轉載於此,以備不時之需。

什麼是事件? 事件(Event)是JavaScript應用跳動的心臟 ,也是把所有東西粘在一起的膠水。當我們與瀏覽器中 Web 頁面進行某些型別的互動時,事件就發生了。事件可能是使用者在某些內容上的點選、滑鼠經過某個特定元素或按下鍵盤上的某些按鍵。事件還可能是 Web

文章6Nginx中的Epoll事件處理機制

0.序      在Linux下,Nginx預設的事件處理機制是Epoll事件處理機制。當然Nginx也可以使用select等事件處理機制,因此Nginx為了支援和開發具體的I/O模型,Nginx將事件處理機制抽象化。      在ngx_epoll_module.c中,可以看到。 1.Epoll事件初

IE和Chrome瀏覽器事件處理的解決辦法

一、事件流 事件流描述的是從頁面中接受事件的順序。 IE的事件流是事件冒泡流,而Netscape的事件流是事件捕獲流 1、事件冒泡 事件冒泡,即事件最開始由最具體的元素(文件中巢狀層次最深的那個節點)

從零開始理解JAVA事件處理機制(2)

extend nds 接下來 htm ref param 簡單 tostring ansi 第一節中的示例過於簡單《從零開始理解JAVA事件處理機制(1)》,簡單到讓大家覺得這樣的代碼簡直毫無用處。但是沒辦法,我們要繼續寫這毫無用處的代碼,然後引出下一階段真正有益的代碼。

關於表單form元素中onsubmit事件處理機制的認識

讓我 clas 教程 是否 它的 默認方法 對象實例 action 事件處理機制   博主目前處於Js學習的初期,遇到了很多問題,比如今天的關於表單form元素中onsubmit事件問題,根據教程所述,onsubmit事件是在表單提交的時候觸發的,但是我看到教程上的onsu

Qt ------ 事件處理機制

後處理 分發 異步 ant ont 事件循環 tar rpo 基類 簡介 在Qt中,事件被封裝成一個個對象,所有的事件均繼承自抽象類QEvent。Qt是以事件驅動UI工具集。Signals/Slots在多線程中的實現也是依賴於Qt的事件處理機制。在Qt中,事件被封裝成一個個

wxPython事件處理機制

參數 過程 Coding vtt nbu roc pre 是我 說明 一直沒有看明白wxPython的自定義事件是如何工作的。如果要自定義事件,那麽需要明白事件源,事件類型,事件處理函數,以及事件綁定器; 但是我在整個過程中沒有看到這幾個概念是如何關聯起來的。下面舉例說明一

3.1.1 基於監聽的事件處理機制

講解 基於 example this apk imp cal href eat 3.1.1 基於監聽的事件處理機制 http://www.runoob.com/w3cnote/android-tutorial-listen-event-handle.html 本節引言:

3.2 基於回調的事件處理機制

return lan 依賴 架構 順序 們的 oncreate 兩個 運行 3.2 基於回調的事件處理機制 http://www.runoob.com/w3cnote/android-tutorial-callback-event-handle.html 1.

JavaScript添加IE事件處理程序

als 不能 type light div 匿名函數 綁定 use gpo   IE和其他主流的瀏覽器之間有很多的不兼容,有一些其他瀏覽器支持的方法在IE中並不能完美的支持,首先哪些支持呢?     1、直接在HTML代碼的元素屬性的位置為事件綁定處理程序;     2、使