e = e || window.event是我們在做事件處理時候區分IE和其他瀏覽器事件對象時常用的寫法。但是這行兼容性代碼有沒有必要出現在所有的事件句柄中呢?標准事件調用方式需要這行代碼嗎?下邊我們做詳細討論。
在討論之前,如果有些忘記或者不熟悉事件對象的先參考其他資料,或者看看這個連接的資料http://wenku.baidu.com/view/400a89f4f61fb7360b4c65ca.html
這里作者把四種主要的事件調用方式總結了出來,本文的討論也是在此之上延伸說明。
<!DOCTYPE HTML>
<html>
<head>
<title></title>
<style type="text/css">
#aa{ border:1px solid #000; width:100px; height:40px; margin-top:50px;}
#bb{ border:1px solid #000; width:500px; height:40px; margin-top:50px;}
#cc{ border:1px solid #000; width:500px; height:40px;}
</style>
</head>
<body>
<div id="aa"></div>
<div id="bb">dfdfddfsd</div>
<div id="cc">gregreger</div>
<script type="text/javascript">
document.getElementById("aa").onclick = function (e) {
if (e) alert(e.toString()); // IE6/7/8 e為undefined IE9中e為W3標准事件對象。
//e = window.event;
alert(e.srcElement.tagName || e.currentTarget.tagName);
}
/* element.onXXX方式(比較古老,不推薦使用)
這種方式添加事件IE6/7/8只支持window.event不支持參數傳入,
Firefox只支持參數傳入不支持其它方式。
IE9/Opera/Safari/Chrome 兩種方式都支持。
*/
var d4 = document.getElementById('bb');
function clk(e) {
alert(e); // 所有瀏覽器彈出的信息框顯示都是事件對象。
alert(e.srcElement.tagName || e.currentTarget.tagName);
e = e || window.event;
alert(e); // IE6/7/8中和上個e彈出相同的對象。
}
if (d4.addEventListener) {
d4.addEventListener('click', clk, false);
alert("addEventListener");
}
if (d4.attachEvent) {
d4.attachEvent('onclick', clk);
alert("attachEvent");
}
/* addEventListener、attachEvent方式(推薦使用)
結論:
通常事件句柄里有這句話:e = e || window.event;
但是在這種調用方式(addEventListener、attachEvent方式)中沒什么作用,
這是什么原因呢?上邊參考文章的總結里指出了原因,即:
“IE6/7/8支持通過window.event獲取對象,
通過attachEvent方式添加事件時也支持事件對象作為句柄第一個參數傳入”
因為IE6/7/8在attachEvent方式添加事件時同時支持兩種方式,所以事件句柄中的參數e在
IE6/7/8中會自動轉換為window.event。
這么以來,這句e = e || window.event;在此處就不需要了(個人結論)。
*/
/*
在編寫跨瀏覽器的函數庫時,IE和標准事件對象的屬性的差異的問題需要解決。
下邊抽出相關代碼,討論這個問題在這里的體現。
*/
var _E = {
BindEvent: function (object, fun) {
if (arguments.length == 1) {
fun = arguments[0];
object = null;
}
var args = Array.prototype.slice.call(arguments, 2);
return function (event) {
return fun.apply(object, [fixEvent(event)].concat(args));
}
}
};
function fixEvent(event) { // 統一不同瀏覽器的event對象
if (event) return event;
event = window.event;
event.pageX = event.clientX + getScrollLeft(event.srcElement);
event.pageY = event.clientY + getScrollTop(event.srcElement);
event.target = event.srcElement;
event.stopPropagation = stopPropagation;
event.preventDefault = preventDefault;
var relatedTarget = {
"mouseout": event.toElement, "mouseover": event.fromElement
}[event.type];
if (relatedTarget) { event.relatedTarget = relatedTarget; }
return event;
};
function stopPropagation() { this.cancelBubble = true; };
function preventDefault() { this.returnValue = false; };
// 測試代碼如下
function get(ev) {
alert(ev.pageX);
}
var cc = document.getElementById("cc");
var clickHandler = _E.BindEvent(get);
cc.attachEvent('onclick', clickHandler); // IE6/7/8下測試
/*
結果點擊id為cc的div元素后,彈出undefined。說明ev.pageX根本不存在。
可是我們在fixEvent()里已經做了事件對象的統一工作。
調試會發現:fixEvent()里if (event) return event;這句是執行后就直接return了,
這里的event按照道理說應該是undefined,但是事實並不是。
//
至於原因個人覺得就是這里:因為IE6/7/8在attachEvent方式添加事件時同時支持兩種方式,
所以事件句柄中的參數會自動轉換為window.event。也就是說參數不是undefined
//
所以在這里用if (event) return event;判斷事件對象不妥。
(說明:fixEvent()這段代碼參考自博客園里cloudgamer的函數庫,
他里邊就是這種寫法,個人覺得有錯誤,希望有興趣的朋友也做做驗證)
*/
</script>
</body>
</html>