国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 編程 > JavaScript > 正文

事件模型在各瀏覽器中存在差異

2019-11-21 00:11:22
字體:
供稿:網(wǎng)友

標(biāo)準(zhǔn)參考

根據(jù) W3C DOM 2 Events 描述,EventTarget 接口被所有支持 DOM 事件模型的節(jié)點(diǎn)(Node)實(shí)現(xiàn)。 該接口提供了 'addEventListener' 和 'removeEventListener' 方法,用來綁定或解綁一個(gè) EventListeners 接口到一個(gè) EventTarget。

DOM 2 Events 中定義了 Event 接口,用來提供事件的上下文信息,它提供了若干標(biāo)準(zhǔn)屬性和方法。 實(shí)現(xiàn) Event 接口的對(duì)象一般作為第一個(gè)參數(shù)傳入事件處理函數(shù),以用來提供當(dāng)前事件相關(guān)的一些信息。

DOM 2 事件模型允許 DOM 實(shí)現(xiàn)支持事件的多模塊,如果有必要,事件模型允許附加新的事件模塊。 為了共同使用性的目的,DOM 會(huì)定義一個(gè)包含低級(jí)別的,依賴設(shè)備的事件模塊、一個(gè) UI 邏輯事件模塊和一個(gè)文檔變化事件模塊的 UI 事件模塊。 第三方實(shí)現(xiàn)(比如瀏覽器廠商)在定義一個(gè)新類型事件的時(shí)候,事件名稱一定不能使用大小寫無關(guān)的 'DOM' 字符串作開頭,該前綴是為未來的 DOM 事件模塊保留的。

DOM 2 已經(jīng)定義了一個(gè) UI 事件類型模塊和一個(gè)鼠標(biāo)事件類型的模塊,它們分別對(duì)應(yīng) UIEvent 和 MouseEvent 接口。 這兩個(gè)接口提供了若干標(biāo)準(zhǔn)屬性和方法,以獲知事件發(fā)生時(shí)的一些信息。

關(guān)于 EventTarget 接口的詳細(xì)信息,請(qǐng)參考 DOM 2 Events 1.3. Event listener registration

關(guān)于 Event 接口的詳細(xì)信息,請(qǐng)參考 DOM 2 Events 1.4. Event interface

關(guān)于事件模塊的詳細(xì)信息,請(qǐng)參考 DOM 2 Events 1.6. Event module definitions

問題描述

各瀏覽器對(duì)元素綁定、解綁事件監(jiān)聽器的方法,事件對(duì)象的獲取,以及 Event 對(duì)象的實(shí)現(xiàn)上存在差異。

造成的影響

如果使用某瀏覽器特有的事件相關(guān)的屬性及方法編寫代碼,則可能造成兼容性問題,導(dǎo)致代碼報(bào)錯(cuò),功能失效。

受影響的瀏覽器

所有瀏覽器 

問題分析

1. 只有 IE Opera 支持使用 'attachEvent' 和 'detachEvent' 方法綁定和解綁事件監(jiān)聽器

根據(jù) DOM 2 Events 中描述,節(jié)點(diǎn)使用 'addEventListener' 和 'removeEventListener' 方法綁定和解綁事件監(jiān)聽器,但 IE6 IE7 IE8 不支持這兩個(gè)方法, 而使用 'attachEvent' 和 'detachEvent' 方法作為替代方案,Opera 兩類方法都支持。Chrome Safari Firefox 只支持標(biāo)準(zhǔn)方法。

分析以下代碼:

<button id="add" type="button">add event listener test</button><button id="remove" type="button">remove event listener test</button><div id="info"></div><script type="text/javascript">	var add = document.getElementById("add"),		remove = document.getElementById("remove"),		showMsgA = function(){showMsg("attachEvent")},		showMsgB = function(){showMsg("addEventListener")};	if(add.attachEvent){		add.attachEvent("onclick",showMsgA);		remove.attachEvent("onclick",removeE);	}	if(add.addEventListener){		add.addEventListener("click",showMsgB,false);		remove.addEventListener("click",removeE,false);	}	function removeE(){		if(add.detachEvent){			add.detachEvent("onclick",showMsgA);			showMsg("detachEvent");		}		if(add.removeEventListener){			add.removeEventListener("click",showMsgB,false);			showMsg("removeEventListener");		}	}	function showMsg(method){		document.getElementById("info").innerHTML += ("support " + method + "<br />");	}</script>

依次點(diǎn)擊 'add event listener test' >> 'remove event listener test' >> 'add event listener test',測(cè)試各瀏覽器對(duì)這些方法的支持,結(jié)果如下:

IE6 IE7 IE8
Opera
Chrome Safari Firefox

關(guān)于 'addEventListener' 和 'attachEvent' 有幾點(diǎn)需要注意:

  • IE 不支持在捕獲階段觸發(fā)事件監(jiān)聽器,'attachEvent' 方法沒有提供參數(shù)說明是否響應(yīng)在捕獲階段觸發(fā)的事件;
  • 'addEventListener' 和 'attachEvent' 都可以注冊(cè)多個(gè)事件監(jiān)聽器;
  • 在 Firefox Chrome Safari Opera 中給同一事件注冊(cè)同一個(gè)事件監(jiān)聽器多次,重復(fù)注冊(cè)的會(huì)被丟棄;而在 IE 中重復(fù)注冊(cè)的事件監(jiān)聽器會(huì)被重復(fù)執(zhí)行多次;
  • 當(dāng)給同一元素注冊(cè)了多個(gè)事件監(jiān)聽器的時(shí)候,IE6 IE7 的事件監(jiān)聽器執(zhí)行順序是隨機(jī)的,IE8 是倒序的,F(xiàn)irefox Chrome Safari Opera 是順序的;
  • 當(dāng)元素注冊(cè)的事件監(jiān)聽器中有非法的事件監(jiān)聽器時(shí)(非函數(shù)),在 IE Firefox 中會(huì)拋出異常,而在 Chrome Safari Opera 中則會(huì)忽略非法的事件監(jiān)聽器,繼續(xù)執(zhí)行其他的事件監(jiān)聽器。

2. 各瀏覽器獲取事件對(duì)象的差異

DOM 2 Events 中規(guī)定使用事件監(jiān)聽器的第一個(gè)參數(shù)作為事件對(duì)象,而 IE Opera Chrome Safari 還支持通過 window.event 獲取事件對(duì)象。

分析以下代碼:

<button type="button" id="attach">attachEvent</button><button type="button" id="addE">addEventListener</button><button type="button" id="byclick">onClick</button><br />INFO :<div id="info"></div><script type="text/javascript">	function $(id){return document.getElementById(id);}	var attach = $("attach"),		addE = $("addE"),		byClick = $("byclick");	attach.attachEvent && attach.attachEvent("onclick", handler);	addE.addEventListener && addE.addEventListener("click", handler, false);	byClick.onclick = handler;	function handler(){		var src = window === this ? window.event.srcElement : this, type = src.innerHTML;		window.event && showMsg(window.event.type, type + " + window.event");		arguments[0] && showMsg(arguments[0].type, type + " + arguments[0]");	}	function showMsg(type, msg){		$("info").innerHTML += (msg + "(type : " + type + ")<br />");	}</script>

以上代碼組合不同的事件監(jiān)聽器綁定方式和事件對(duì)象獲取方法,測(cè)試各瀏覽器的支持程度。

依次點(diǎn)擊 'attachEvent' >> 'addEventListener' >> 'onClick',結(jié)果如下:

IE6 IE7 IE8
Chrome Safari
Opera
Firefox

匯總測(cè)試結(jié)果如下表:1

事件對(duì)象獲取方式IE6 IE7 IE8Chrome SafariOperaFirefox
window.eventYYYN
arguments[0]Y2YYY

注1: Y 表示支持該事件對(duì)象獲取方式,N 表示不支持。

注2: 部分支持。

從上表出可以看出:

  • 只有在使用 attachEvent 方法注冊(cè)事件監(jiān)聽器的時(shí)候,IE 才支持使用事件監(jiān)聽器傳入的第一個(gè)參數(shù)作為事件對(duì)象的方式;
  • Chrome Safari Opera 兩種獲取事件對(duì)象的方式都支持;
  • Firefox 只支持獲取事件對(duì)象的標(biāo)準(zhǔn)方式。

3. 各瀏覽器中事件對(duì)象的屬性和方法的差異

IE 對(duì)事件對(duì)象的標(biāo)準(zhǔn)屬性和方法支持有限,針對(duì)大部分屬性和方法,IE 都提供了一套替代非標(biāo)準(zhǔn)的替代方案; 而 Firefox Chrome Safari Opera 除了全面支持事件對(duì)象的標(biāo)準(zhǔn)屬性和方法外,還在不同程度上支持了 IE 提供的非標(biāo)準(zhǔn)替代方案。

以下代碼檢測(cè)了 Event、UIEvent、MouseEvent 接口以及事件對(duì)象的非標(biāo)準(zhǔn)屬性在各瀏覽器下的支持程度:

<button type="button" id="iEvent">Interface Event</button><button type="button" id="iUIMouse">Interface UIEvent & MouseEvent</button><input type="text" id="nosK" /><p id="wrap" style="border:3px solid;padding:5px;width:500px;"><a id="nosCM" href="#"><img src="google.gif" alt="IE"/></a></p><br /><table border="1">	<tbody>		<tr>			<th>Interface Event</th>			<td id="einfo"></td>		</tr>		<tr>			<th>Interface UIEvent<br/>&<br/>MouseEvent</th>			<td id="minfo"></td>		</tr>		<tr>			<th>Non-standard<br/>&<br/>click</th>			<td id="ncinfo"></td>		</tr>		<tr>			<th>Non-standard<br/>&<br/>mouseover mouseout</th>			<td id="nminfo"></td>		</tr>		<tr>			<th>Non-standard<br/>&<br/>keyCode</th>			<td id="nkinfo"></td>		</tr>	</tbody></table><script type="text/javascript">	function $(id){return document.getElementById(id);}	function addEvent(elem, type, handler, useCapture){		elem.addEventListener ? elem.addEventListener(type, handler, useCapture) :			elem.attachEvent("on" + type, handler);	}	addEvent($("iEvent"), "click", handleEvent, false);	addEvent($("iUIMouse"), "click", handleUIMouse, false);	addEvent($("nosCM"), "click", handleNoSClick, false);	addEvent($("wrap"), "click", function(){alert("P tag.");}, false);	addEvent($("nosCM"), "mouseover", handldNoSMouse, false);	addEvent($("nosCM"), "mouseout", handldNoSMouse, false);	addEvent($("nosK"), "keydown", handleNoSKey, false);	addEvent($("nosK"), "keypress", handleNoSKey, false);	addEvent($("nosK"), "keyup", handleNoSKey, false);	function handleEvent(e){		e = e || window.event;		var props = {			type : "type",			target : "target",			currentTarget : "currentTarget",			eventPhase : "eventPhase",			bubbles : "bubbles",			cancelable : "cancelable",			timeStamp : "timeStamp",			initEvent : "initEvent",			preventDefault : "preventDefault",			stopPropagation : "stopPropagation"		};		showMsg(props, e, $("einfo"));	}	function handleUIMouse(e){		e = e || window.event;		var props = {			view : "view",			detail : "detail",			initUIEvent : "initUIEvent",			screenX: "screenX",			screenY : "screenY",			clientX : "clientX",			clientY : "clientY",			ctrlKey : "ctrlKey",			shiftKey : "shiftKey",			altKey : "altKey",			metaKey : "metaKey",			button : "button",			relatedTarget : "relatedTarget",			initMouseEvent : "initMouseEvent"		}		showMsg(props, e, $("minfo"));	}	function handleNoSClick(e){		e = e || window.event;		e.returnValue = false;		e.cancelBubble = true;		var props = {			cancelBubble : "cancelBubble",			offsetX : "offsetX",			offsetY : "offsetY",			returnValue : "returnValue",			srcElement : "srcElement",			x : "x",			y : "y"		};		showMsg(props, e, $("ncinfo"));	}	function handldNoSMouse(e){		e = e || window.event;		var props = {			fromElement : "fromElement",			toElement : "toElement"		};		showMsg(props, e, $("nminfo"));	}	function handleNoSKey(e){		e = e || window.event;		$("nkinfo").innerHTML += "<strong>" + e.type + "</strong> : " + e.keyCode + "<br/>";	}	function showMsg(props, e, info){		var tmp = "", p, val;		with(e){			for(p in props) {				try{					val = eval(props[p]) + " [" + typeof eval(props[p]) + "]";				} catch (e) {					val = undefined;				}				tmp += "<strong>" + p + "</strong> : " + val + "<br />"			}		}		info.innerHTML = tmp;	}</script>

執(zhí)行以上測(cè)試代碼,分別點(diǎn)擊 'Interface Event' 按鈕、'Interface UIEvent & MouseEvent' 按鈕和圖片,鼠標(biāo)移到圖片上再移開,在文本框中輸入 'a',得到結(jié)果整理如下表:3

Interface & Non-standardProperty & methodIE6 IE7 IE8Chrome Safari OperaFirefox
Interface EventtypeYYY
targetNYY
currentTargetNYY
eventPhaseNYY
bubblesNYY
cancelableNYY
timeStampNYY
initEventNYY
preventDefaultNYY
stopPropagationNYY
Interface UIEventviewNYY
detailNYY
initUIEventNYY
Interface MouseEventscreenXYYY
screenYYYY
clientXYYY
clientYYYY
ctrlKeyYYY
shiftKeyYYY
altKeyYYY
metaKeyNYY
buttonYYY
relatedTargetNYY
initMouseEventNYY
Non-standardcancelBubbleYYY
offsetXYYN
offsetYYYN
returnValueYYN
srcElementYYN
xYYN
yYYN
fromElementYYN
toElementYYN
keyCodeYYY

注3: Y 代表事件對(duì)象支持該屬性或方法,N 代表不支持。

從上表中可以看出:

  • IE 支持事件對(duì)象的所有非標(biāo)準(zhǔn)屬性,不支持除 'type' 外 Event 接口的所有方法屬性及方法,不支持 UIEvent 接口的所有屬性和方法,不支持 MouseEvent 接口的 'metaKey'、'relatedTarget' 屬性和 'initMouseEvent' 方法;
  • Chrome Safari Opera 支持事件對(duì)象的所有標(biāo)準(zhǔn)及非標(biāo)準(zhǔn)的屬性和方法;
  • Firefox 支持事件對(duì)象的所有標(biāo)準(zhǔn)屬性和方法,但僅支持非標(biāo)準(zhǔn)屬性中的 'cancelBubble' 和 'keyCode'。

需要注意的是:

  • Firefox 不支持事件對(duì)象的 'returnValue' 屬性,測(cè)試樣例中雖然顯示 'returnValue' 值為 false,但這僅僅是因?yàn)榻o事件對(duì)象添加了 'returnValue' 屬性,并沒有起到取消事件默認(rèn)動(dòng)作的作用,這從地址欄可以看出,多了 '#' 號(hào),這是 A 標(biāo)簽的 'href' 屬性造成的。
  • 各瀏覽器對(duì) Event 接口的 'timeStamp' 屬性返回值都不同。

關(guān)于 IE 實(shí)現(xiàn)的事件對(duì)象非標(biāo)準(zhǔn)的屬性及方法的詳細(xì)信息,請(qǐng)參考 MSDN event Object

關(guān)于 Firefox 對(duì)事件對(duì)象實(shí)現(xiàn)的詳細(xì)信息,請(qǐng)參考 MDC event

解決方案

1. 使用特性判斷創(chuàng)建無兼容性問題的事件監(jiān)聽器綁定和解綁函數(shù)

如:

function addEvent(elem, type, handler, useCapture){	elem.addEventListener ? elem.addEventListener(type, handler, useCapture) :		elem.attachEvent("on" + type, handler);}function removeEvent(elem, type, handler, useCapture){	elem.removeEventListener ? elem.removeEventListener(type, handler, useCapture) :		elem.detachEvent("on" + type, handler);}

2. 使用特性判斷獲得有效的事件對(duì)象

在事件監(jiān)聽器中判斷傳入的第一個(gè)參數(shù)或 window.event 是否有效,如:

function handler(e){	e = e || window.event;}

3. 使用特性判斷使用與標(biāo)準(zhǔn)對(duì)應(yīng)的非標(biāo)準(zhǔn)方法及屬性

盡管 IE 對(duì)事件對(duì)象的標(biāo)準(zhǔn)屬性和方法支持有限,但它自己實(shí)現(xiàn)的事件模型也基本能夠替代或?qū)崿F(xiàn)標(biāo)準(zhǔn)屬性或方法的功能。

下表總結(jié)了部分與標(biāo)準(zhǔn)事件對(duì)象對(duì)應(yīng)的,或可以實(shí)現(xiàn)標(biāo)準(zhǔn)屬性或方法功能的非標(biāo)準(zhǔn)屬性:

StandardNon-standard
targetsrcElement
preventDefault()returnValue
stopPropagation()cancelBubble
relatedTargetfromElement toElement

另,標(biāo)準(zhǔn)的 'clientX' 屬性和非標(biāo)準(zhǔn)的 'x' 屬性作用是相同的,同樣 'clientY' 和 'y' 也是。

發(fā)表評(píng)論 共有條評(píng)論
用戶名: 密碼:
驗(yàn)證碼: 匿名發(fā)表
主站蜘蛛池模板: 彭水| 锦屏县| 本溪市| 凌源市| 上虞市| 夏河县| 砚山县| 临湘市| 岳池县| 阿鲁科尔沁旗| 霍城县| 勃利县| 大悟县| 麻城市| 西贡区| 隆子县| 思南县| 襄垣县| 镇赉县| 兴业县| 射洪县| 锡林郭勒盟| 明星| 虞城县| 定结县| 萨嘎县| 凤凰县| 武宣县| 阆中市| 南安市| 东源县| 临沭县| 牙克石市| 泰兴市| 元朗区| 青冈县| 云阳县| 绥德县| 北辰区| 枣强县| 临清市|