跨瀏覽器的事件兼容

我們都知道,在不同的瀏覽器下,添加和移除事件處理程序方式有所相同,要想寫出跨瀏覽器的事件處理程序,首先我們要了解不同的瀏覽器下處理事件處理程序的區(qū)別

在添加事件處理程序時addEventListener和attachEvent主要有以下幾個區(qū)別

  1. 參數(shù)個數(shù)不相同,這個最直觀,addEventListener有三個參數(shù),attachEvent只有兩個,attachEvent添加的事件處理程序只能發(fā)生在冒泡階段,addEventListener第三個參數(shù)可以決定添加的事件處理程序是在捕獲階段還是冒泡階段處理(我們一般為了瀏覽器兼容性都設置為冒泡階段)

  2. 第一個參數(shù)意義不同,addEventListener第一個參數(shù)是事件類型(比如click,load),而attachEvent第一個參數(shù)指明的是事件處理函數(shù)名稱(onclick,onload)

  3. 事件處理程序的作用域不相同,addEventListener的作用域是元素本身,this是指的觸發(fā)元素,而attachEvent事件處理程序會在全局變量內運行,this是window,所以剛才例子才會返回undefined,而不是元素id

  4. 為一個事件添加多個事件處理程序時,執(zhí)行順序不同,addEventListener添加會按照添加順序執(zhí)行,而attachEvent添加多個事件處理程序時順序無規(guī)律(添加的方法少的時候大多是按添加順序的反順序執(zhí)行的,但是添加的多了就無規(guī)律了),所以添加多個的時候,不依賴執(zhí)行順序的還好,若是依賴于函數(shù)執(zhí)行順序,最好自己處理,不要指望瀏覽器去解決。

了解了這四點區(qū)別后我們可以嘗試寫一個瀏覽器兼容性比較好的添加事件處理程序方法

function addEvent(node, type, handler) {
    if (!node) return false;
    if (node.addEventListener) {
        node.addEventListener(type, handler, false);
        return true;
    }
    else if (node.attachEvent) {
        node.attachEvent('on' + type, handler, );
        return true;
    }
    return false;
}

這樣,我們解決了兩個問題

  1. 參數(shù)個數(shù)不同,現(xiàn)在是三個參數(shù),
  2. 現(xiàn)在都在事件冒泡階段觸發(fā)
  3. 第二個問題也得以解決,如果是IE,我們給type添加上on

但是如果handler內有關于this操作的話,this指向依然是不同的,執(zhí)行順序的問題也還沒有解決方案,這里需要我們自己注意,一般情況下,同一個對象不會添加很多事件處理程序。

*接下來,我們來嘗試解決this指向問題:

function addEvent(node, type, handler) {
    if (!node) return false;
    if (node.addEventListener) {
        node.addEventListener(type, handler, false);
        return true;
    }
    else if (node.attachEvent) {
        node.attachEvent('on' + type, function() { handler.apply(node); });
        return true;
    }
    return false;
}

通過apply(),this指向了事件目標,但是新的問題又來了,我們這樣等于添加了一個匿名的事件處理程序,無法用detachEvent取消事件處理程序,有很多解決方案,我們可以借鑒大師的處理方式,jQuery創(chuàng)始人John Resig是這樣做的

function addEvent(node, type, handler) {
    if (!node) return false;
    if (node.addEventListener) {
        node.addEventListener(type, handler, false);
        return true;
    }
    else if (node.attachEvent) {
        node['e' + type + handler] = handler;  //handler中的this指向node 即事件目標
        node[type + handler] = function() {
            node['e' + type + handler](window.event);
        };
        node.attachEvent('on' + type, node[type + handler]);   //調用handler函數(shù),并且傳入事件對象作為參數(shù)
        return true;
    }
    return false;
}

在取消事件處理程序的時候

function removeEvent(node, type, handler) {
    if (!node) return false;
    if (node.removeEventListener) {
        node.removeEventListener(type, handler, false);
        return true;
    }
    else if (node.detachEvent) {
        node.detachEvent('on' + type, node[type + handler]);
        node[type + handler] = null;
    }
    return false;
}

這里很巧妙地利用了閉包,看起來很不錯。

事件對象的不同屬性方法

*DOM中的事件對象和IE中的事件對象有不同的屬性/方法

首先是DOM中事件對象有不同的屬性/方法:

屬性/方法 類型 讀/寫 方法
bubbles Boolean 只讀 事件是否冒泡
cancelable Boolean 只讀 事件是否冒泡
currentTarget Element 只讀 事件處理程序當前處理元素
detail Integer 只讀 與事件相關細節(jié)信息
eventPhase Integer 只讀 事件處理程序階段:1 捕獲階段,2 處于目標階段,3 冒泡階段
preventDefault() Function 只讀 取消事件默認行為
stopPropagation() Function 只讀 取消事件進一步捕獲或冒泡
target Element 只讀 事件的目標元素
type String 只讀 被觸發(fā)的事件類型
view AbstractView 只讀 與事件關聯(lián)的抽象視圖,等同于發(fā)生事件的window對象

然后是IE中的:

屬性/方法 類型 讀/寫 方法
cancelBubble Boolean 讀/寫 默認為false,設置為true后可以取消事件冒泡
returnValue Boolean 讀/寫 默認為true,設為false可以取消事件默認行為
srcElement Element 只讀 事件的目標元素
type String 只讀 被觸發(fā)的事件類型

雖然DOM和IE的event對象不同,但基于它們的相似性,我們還是可以寫出跨瀏覽器的事件對象方案,可以不用擔心瀏覽器的問題會影響我們功能的實現(xiàn)

function getEvent(e) {
    return e || window.event;
}

function getTarget(e) {
    return e.target || e.scrElement;
}

function preventDefault(e) {
    if (e.preventDefault)
        e.preventDefault();
    else
        e.returnValue = false;
}

function stopPropagation(e) {
    if (e.stopPropagation)
        e.stopPropagation();
    else
        e.cancelBubble = true;
}

*備注:關于事件相關的兼容

onclick-----------------------------------------都支持
attachEvent()-----------------------------------IE8
addEventListener()------------------------------IE9以前不支持
stopPropagation();preventDefault()--------------IE9以前不支持
returnValue-------------------------------------不支持preventDefault()方法取消默認行為時的解決方法
cancelBubble=true-------------------------------不支持stopPropagation()方法阻止冒泡時的解決方法
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發(fā)布,文章內容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容