1、事件就是用戶或瀏覽器自身執行的某種動作。
2、事件處理程序(或事件監聽器)就是響應某個事件的函數。
HTML事件處理程序
//HTML中定義的事件處理程序包含要執行的具體動作
//這個值是JavaScript,所以不能再其中使用未經轉義的HTML語法字符,例如& "" < >
<input type="button" value="確定" onclick="alert('clicked')" />
<input type="button" value="確定" onclick="alert("clicked")" />
//HTML中定義的事件處理程序也可以調用在頁面其他地方定義的腳本
<script type="text/javascript">
function showMessage() {
alert("Hello world!");
}
</script>
<input type="button" value="確定" onclick="showMessage()" />
缺點:
-
存在一個時差問題。因為用戶可能會在HTML元素一出現在頁面上就觸發相應的事件,但當時的事件處理程序有可能尚不具備執行條件。
- 為此,很多HTML事件處理程序會被封裝在一個try-catch塊中,以便用戶不會看到JavaScript錯誤,因為在瀏覽器有機會處理錯誤之前,錯誤就被捕獲了。
<input type="button" value="確定" onclick="try{showMessage()}catch(ex){}"/>
- 為此,很多HTML事件處理程序會被封裝在一個try-catch塊中,以便用戶不會看到JavaScript錯誤,因為在瀏覽器有機會處理錯誤之前,錯誤就被捕獲了。
這樣擴展事件處理程序的作用域鏈在不同瀏覽器中會導致不同結果。不同JavaScript引擎遵循的標識符解析規則略有差異,很可能會在訪問非限定對象成員時出錯。
HTML與JavaScript代碼緊密耦合,如果要更換事件處理程序就要改動兩個地方:HTML代碼和JavaScript代碼。(著正是許多開發人員摒棄HTML事件處理程序,轉而使用JavaScript指定事件處理程序的原因所在。)
DOM0 級事件處理程序
通過JavaScript指定事件處理程序的傳統方式:
將一個函數賦值給一個事件處理程序屬性。
優點:
- 簡單。
- 具有跨瀏覽器的優勢。
每個元素(包括window和document)都有自己的事件處理程序屬性,這些屬性通常全部消協。將這種屬性的值設置為一個函數,就可以指定事件處理程序:
var btn = document.getElementById("myBtn");
btn.onclick = function () {
alert(this.id); //myBtn
}
使用DOM0 級方法指定的事件處理程序被認為是元素的方法。因此,是在元素的作用域中運行的,即程序中的this引用當前元素。
也可以刪除通過 DOM0 級方法指定的事件處理程序:
btn.onclick = null; //刪除事件處理程序
DOM2 級事件處理程序
定義了兩個方法:
- addEventListener()
- removeEventListener()
addEventListener()方法
/**
* addEventListener()
* param:
* param1——要處理的事件名
* param2——作為事件處理程序的函數
* param3——一個布爾值:
* true,表示捕獲階段調用事件處理程序;
* false,表示冒泡階段調用事件處理程序。
*/
var btn = document.getElementById("myBtn");
btn.addEventListener("click",function () {
alert(this.id);
},false);
btn.addEventListener("click",function () {
alert("hello world");
},false);
使用DOM2 級方法添加事件處理程序的主要好處就是可以添加多個事件處理程序,按照添加它們的順序觸發。
removeEventListener()
通過addEventListener()添加的事件處理程序只能使用removeEventListener()來移除;移除時傳入的參數與添加處理程序時使用的參數相同。
通過addEventListener()添加的匿名函數將無法移除。
var btn = document.getElementById("myBtn");
btn.addEventListener("click",function () {
alert(this.id);
},false);
//.....
btn.removeEventListener("click",function(){ //沒有用?。。? alert(this.id);
},false);
//修改后:
var btn = document.getElementById("myBtn");
var handler = function(){
alert(this.id);
};
btn.addEventListener("click",handler,false);
//.....
btn.removeEventListener("click",handler,false);
IE 事件處理程序
IE 實現了與 DOM 中類似的兩個方法:
- attachEvent()
- detachEvent()
這兩個方法接受相同的兩個參數:事件處理程序名稱與事件處理程序函數。
由于 IE8 及更早版本只支持事件冒泡,所以通過 attachEvent() 添加的事件處理程序都會被添加到冒泡階段。
var btn = document.getElementById("myBtn");
btn.attachEvent("onclick", function(){
console.log("Clicked");
});
注意,attachEvent() 的第一個參數是 "onclick",而非 DOM 的 addEventListener() 方法中的 "click"。
在 IE 中使用 attachEvent() 與使用 DOM0 級方法的主要區別:事件處理程序的作用域。
- 在使用 DOM0 級方法的情況下,事件處理程序會在其所屬元素的作用域內運行;
- 在使用 attachEvent() 方法的情況下,事件處理程序會在全局作用域中運行,因此 this 等于 window。
var btn = document.getElementById("myBtn");
btn.attachEvent("onclick", function(){
console.log(this === window); // true
});
attachEvent() 方法也可以用來為一個元素添加多個事件處理程序。不過,與 DOM 方法不同的是,這些事件處理程序不是以添加它們的順序執行,而是以相反的順序被觸發。
使用 attachEvent() 添加的事件可以通過 detachEvent() 來移除,條件是必須提供相同的參數。與 DOM 方法一樣,這也意味著添加的匿名函數將不能被移除。不過,只要能夠將對相同函數的引用傳給 detachEvent(),就可以移除相應的事件處理程序。
支持 IE 事件處理程序的瀏覽器有 IE 和 Opera。
跨瀏覽器的事件處理程序
要保證處理事件的代碼能在大多數瀏覽器下一致地運行,只需關注冒泡階段。
var EventUtil = {
//addHandler() 方法接受3個參數:要操作的元素、事件名稱和事件處理程序函數。
addHandler: function(element, type, handler){
if (element.addEventListener){
element.addEventListener(type, handler, false);
} else if (element.attachEvent){
element.attachEvent("on" + type, handler);
} else {
element["on" + type] = handler;
}
},
//removeHandler() 方法接受3個參數:要操作的元素、事件名稱和事件處理程序函數。
removeHandler: function(element, type, handler){
if (element.removeEventListener){
element.removeEventListener(type, handler, false);
} else if (element.detachEvent){
element.detachEvent("on" + type, handler);
} else {
element["on" + type] = null;
}
}
};
這兩個方法首先都會檢測傳入的元素中是否存在 DOM2 級方法。如果存在 DOM2 級方法,則使用該方法:傳入事件類型、事件處理程序函數和第三個參數 false(表示冒泡階段)。如果存在的是 IE 的方法,則采取第二種方案。注意,為了在 IE8 及更早版本中運行,此時的事件類型必須加上 "on" 前綴。最后一種可能就是使用 DOM1 級方法(在現代瀏覽器中,應該不會執行這里的代碼)。