Internet Explorer 事件模型



Internet Explorer 並不支援 DOM Level 2 事件模型,而是有個類似DOM Level 2事件模型的專屬方式,由於只有Internet Explorer上才有,通常稱之模為Internet Explorer事件模型

在Internet Explorer上若要使用進階的註冊模型,必須使用attachEvent()detachEvent()方法,而且要注意,被呼叫的事件處理器函式,在事件發生時會以全域的方式呼叫,也就是說,this一定是參考至全域物件,不幸的是,Internet Explorer事件模型中,Event實例上並沒有如DOM Level 2事件模型的currentTarget特性,可以讓你取得目前觸發事件的元素。

如果你想要取得目前觸發事件的元素,方式是用某種方式讓函式綁定該元素。方法之一是直接綁定this參考的對象,例如設計一個proxy()函式:
function proxy(element, handler) {
    return function() {
        return handler.apply(element, arguments);
    };
}

proxy()會產生一個函式實例,函式本體中使用apply()方法呼叫傳入的處理器函式,並指定第一個參數為傳入的element,這個element就是你想在處理器中this綁定的對象。

結合這個proxy()函式,可以改寫
DOM Level 2 事件模型 中第一個範例如下,由於是Internet Explorer專屬事件模型,所以只有Internet Explorer可以執行以下範例:
<html>
<head>
<title>InternetExplorerEventModel-1</title>
<meta content="text/html; charset=UTF-8" http-equiv="content-type">
<script type="text/javascript">
window.attachEvent('onload', function() {
function proxy(element, handler) {
return function() {
return handler.apply(element, arguments);
};
}
function handler() {
document.getElementById('console').innerHTML
= 'Who\'s clicked: ' + this.id;
}
var btn1 = document.getElementById('btn1');
btn1.attachEvent('onclick', proxy(btn1, handler));

var btn2 = document.getElementById('btn2');
btn2.attachEvent('onclick', proxy(btn2, handler));
});
</script>
</head>
<body>
<button id="btn1">按鈕一</button><br>
<button id="btn2">按鈕二</button><br>
<div id="console"></div>
</body>
</html>

注意,attachEvent()的第一個參數指定要註冊的事件類型,而且必須有個'on'開頭,第二個參數是要註冊的事件處理器函式,與DOM Level 2事件模型不同的是,沒有第三個參數,因為Internet Explorer沒有捕捉階段,只有事件浮昇

有些事件有預設的動作,若要停止預設動作,在Internet Explorer事件模型下可以從事件處理器中傳回false,或者是將Event實例的returnValue設為false。例如可改寫 DOM Level 2 事件模型 中第二個表單驗證範例
<html>
<head>
<title>InternetExplorerEventModel-2</title>
<meta content="text/html; charset=UTF-8" http-equiv="content-type">
<script type="text/javascript">
window.attachEvent('onload', function() {
function proxy(element, handler) {
return function() {
return handler.apply(element, arguments);
};
}
var form = document.form1;
form.attachEvent('onsubmit', proxy(form, function() {
if(this.data.value.length === 0) {
window.event.returnValue = false;
}
}));
});
</script>
</head>
<body>
<form name="form1" action="fake.do">
輸入資料:<input name="data"><br>
<button type="submit">送出</button>
</form>
</body>
</html>

在Internet Explorer中,Event實例對是window上的event特性所參考,而非作為事件處理器第一個參數傳入。Internet Explorer僅支援事件浮昇,如果想取得操作的目標物件,必須使用Event實例的srcElement特性。例如,可改寫 DOM Level 2 事件模型 中第三個範例來觀察事件浮昇:
<html>
<head>
<title>InternetExplorerEventModel-3</title>
<meta content="text/html; charset=UTF-8" http-equiv="content-type">
<script type="text/javascript">
window.attachEvent('onload', function() {
function proxy(element, handler) {
return function() {
return handler.apply(element, arguments);
};
}
function handler() {
document.getElementById('console').innerHTML +=
'<br><b>this.id:</b> ' + this.id +
', <b>srcElement.id:</b> ' + window.event.srcElement.id;
}
var body = document.getElementById('bodyId');
body.attachEvent('onclick', proxy(body, handler));

var div = document.getElementById('divId');
div.attachEvent('onclick', proxy(div, handler));

var btn = document.getElementById('btnId');
btn.attachEvent('onclick', proxy(btn, handler));
});
</script>
</head>
<body id="bodyId">
<div id="divId"><button id="btnId">按我</button></div>
<span id="console"></span>
</body>
</html>

如果按下按鈕,會發現以下的結果,可發現事件從內往外傳播:
this.id: btnId, srcElement.id: btnId
this.id: divId, srcElement.id: btnId
this.id: bodyId, srcElement.id: btnId

如果你想要停止事件傳播,必須設定Event的cancelBubble。例如上一個範例若要停止目標元素外的事件傳播,可以如下:
<html>
<head>
<title>InternetExplorerEventModel-4</title>
<meta content="text/html; charset=UTF-8" http-equiv="content-type">
<script type="text/javascript">
window.attachEvent('onload', function() {
function proxy(element, handler) {
return function() {
return handler.apply(element, arguments);
};
}
function handler() {
document.getElementById('console').innerHTML +=
'<br><b>this.id:</b> ' + this.id +
', <b>srcElement.id:</b> ' + window.event.srcElement.id;
window.event.cancelBubble = true;
}
var body = document.getElementById('bodyId');
body.attachEvent('onclick', proxy(body, handler));

var div = document.getElementById('divId');
div.attachEvent('onclick', proxy(div, handler));

var btn = document.getElementById('btnId');
btn.attachEvent('onclick', proxy(btn, handler));
});
</script>
</head>
<body id="bodyId">
<div id="divId"><button id="btnId">按我</button></div>
<span id="console"></span>
</body>
</html>