跨瀏覽器的事件兼容

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

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

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

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

  3. 事件處理程序的作用域不相同前痘,addEventListener的作用域是元素本身凛捏,this是指的觸發(fā)元素,而attachEvent事件處理程序會在全局變量內(nèi)運行芹缔,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內(nèi)有關(guān)于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指向了事件目標(biāo)疫诽,但是新的問題又來了舅世,我們這樣等于添加了一個匿名的事件處理程序旦委,無法用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 即事件目標(biāo)
        node[type + handler] = function() {
            node['e' + type + handler](window.event);
        };
        node.attachEvent('on' + type, node[type + handler]);   //調(diào)用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 只讀 事件處理程序當(dāng)前處理元素
detail Integer 只讀 與事件相關(guān)細(xì)節(jié)信息
eventPhase Integer 只讀 事件處理程序階段:1 捕獲階段,2 處于目標(biāo)階段奕短,3 冒泡階段
preventDefault() Function 只讀 取消事件默認(rèn)行為
stopPropagation() Function 只讀 取消事件進(jìn)一步捕獲或冒泡
target Element 只讀 事件的目標(biāo)元素
type String 只讀 被觸發(fā)的事件類型
view AbstractView 只讀 與事件關(guān)聯(lián)的抽象視圖宜肉,等同于發(fā)生事件的window對象

然后是IE中的:

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

雖然DOM和IE的event對象不同谬返,但基于它們的相似性,我們還是可以寫出跨瀏覽器的事件對象方案日杈,可以不用擔(dān)心瀏覽器的問題會影響我們功能的實現(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;
}

*備注:關(guān)于事件相關(guān)的兼容

onclick-----------------------------------------都支持
attachEvent()-----------------------------------IE8
addEventListener()------------------------------IE9以前不支持
stopPropagation();preventDefault()--------------IE9以前不支持
returnValue-------------------------------------不支持preventDefault()方法取消默認(rèn)行為時的解決方法
cancelBubble=true-------------------------------不支持stopPropagation()方法阻止冒泡時的解決方法
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末遣铝,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子莉擒,更是在濱河造成了極大的恐慌酿炸,老刑警劉巖,帶你破解...
    沈念sama閱讀 218,284評論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件涨冀,死亡現(xiàn)場離奇詭異填硕,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)鹿鳖,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,115評論 3 395
  • 文/潘曉璐 我一進(jìn)店門扁眯,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人翅帜,你說我怎么就攤上這事姻檀。” “怎么了涝滴?”我有些...
    開封第一講書人閱讀 164,614評論 0 354
  • 文/不壞的土叔 我叫張陵绣版,是天一觀的道長。 經(jīng)常有香客問我歼疮,道長杂抽,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,671評論 1 293
  • 正文 為了忘掉前任腋妙,我火速辦了婚禮默怨,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘骤素。我一直安慰自己匙睹,他們只是感情好愚屁,可當(dāng)我...
    茶點故事閱讀 67,699評論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著痕檬,像睡著了一般霎槐。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上梦谜,一...
    開封第一講書人閱讀 51,562評論 1 305
  • 那天丘跌,我揣著相機(jī)與錄音,去河邊找鬼唁桩。 笑死闭树,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的荒澡。 我是一名探鬼主播报辱,決...
    沈念sama閱讀 40,309評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼单山!你這毒婦竟也來了碍现?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,223評論 0 276
  • 序言:老撾萬榮一對情侶失蹤米奸,失蹤者是張志新(化名)和其女友劉穎昼接,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體悴晰,經(jīng)...
    沈念sama閱讀 45,668評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡慢睡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,859評論 3 336
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了膨疏。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片一睁。...
    茶點故事閱讀 39,981評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡钻弄,死狀恐怖佃却,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情窘俺,我是刑警寧澤饲帅,帶...
    沈念sama閱讀 35,705評論 5 347
  • 正文 年R本政府宣布,位于F島的核電站瘤泪,受9級特大地震影響灶泵,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜对途,卻給世界環(huán)境...
    茶點故事閱讀 41,310評論 3 330
  • 文/蒙蒙 一赦邻、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧实檀,春花似錦惶洲、人聲如沸按声。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,904評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽签则。三九已至,卻和暖如春铐料,著一層夾襖步出監(jiān)牢的瞬間渐裂,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,023評論 1 270
  • 我被黑心中介騙來泰國打工钠惩, 沒想到剛下飛機(jī)就差點兒被人妖公主榨干…… 1. 我叫王不留柒凉,地道東北人。 一個月前我還...
    沈念sama閱讀 48,146評論 3 370
  • 正文 我出身青樓篓跛,卻偏偏與公主長得像扛拨,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子举塔,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,933評論 2 355

推薦閱讀更多精彩內(nèi)容

  • JavaScript 程序采用了異步事件驅(qū)動編程模型绑警。在這種程序設(shè)計風(fēng)格下,當(dāng)文檔央渣、瀏覽器计盒、元素或與之相關(guān)的對象發(fā)...
    劼哥stone閱讀 1,256評論 3 11
  • 以下文章為轉(zhuǎn)載,對理解JavaScript中的事件處理機(jī)制很有幫助芽丹,淺顯易懂北启,特分享于此。 什么是事件拔第? 事件(E...
    jxyjxy閱讀 3,037評論 1 10
  • 聲明:本文來源于http://www.webzsky.com/?p=731我只是在這里作為自己的學(xué)習(xí)筆記整理一下(...
    angryyan閱讀 7,012評論 1 6
  • Spring Cloud為開發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見模式的工具(例如配置管理咕村,服務(wù)發(fā)現(xiàn),斷路器蚊俺,智...
    卡卡羅2017閱讀 134,657評論 18 139
  • 2017.1.20 行動派紫微 原來泳猬,西安這么好 兩件事情的發(fā)生批钠,讓我重新想要去找到對西安的愛。 第一得封,前段時間我...
    作家阿紫閱讀 158評論 0 4