事件就是用戶或瀏覽器自身執行的某種動作,例如click、load等,都是事件的名字,響應事件的函數叫做事件處理程序,事件處理程序的名字以“on”開頭,例如click事件的事件處理程序就是onload。
HTML事件處理程序
每個元素支持的每種事件,都可以使用一個與相應事件處理程序同名的HTML特性來指定。例如:要讓按鈕被單擊時執行一些javascript,代碼如下:
<script type="text/javascript">
function showMessage(){
alert("hello world!");
}
<input type="button" value="Click Me" onclick="showMessage()" />
showMessage()函數是在一個獨立的<script>元素中定義的,也可以包含在一個外部文件中,這樣做有一些特點:
- 獨到之處
- 會創建一個封裝著元素屬性值的函數,這個函數中有一個局部變量event(事件對象)
- 在這個函數內部,this值等于事件的目標元素
- 問題
- 存在時差問題
- 這樣擴展事件處理程序的作用域鏈在不同的瀏覽器會導致不同結果
- HTML與javascript代碼緊密耦合,如果要更換事件處理程序,則要改動HTML代碼和javascript代碼兩個部分(因為js代碼和元素是對應的),所以開發人員從HTML事件處理程序轉向使用Javascript指定事件處理程序。
DOM0級事件處理程序
通過JavaScript指定事件處理程序的傳統方法,就是將一個函數賦值給一個事件處理程序屬性。
- 每個元素(包括window和document)都有自己的事件處理程序屬性,這些屬性通常全部小寫,如onclick。將這種屬性的值設為一個函數,就可以指定事件處理程序。
var btn=document.getElementById("myBtn");
btn.onclick=function(){
alert("Clicked");
};
注意:在這些代碼運行前不會指定事件處理程序,因為如果這些代碼在頁面中位于按鈕后面,就有可能在一段時間內怎么點擊都沒有反應。
- 使用DOM0級方法指定的事件處理程序被認為是元素的方法。因此,這時候的事件處理程序是在元素的作用域中運行;換句話說,程序的this引用當前元素。可以在事件處理程序中通過this訪問元素的任何屬性和方法。
var btn=document.getElementById("myBtn");
btn.onclick=function(){
alert(this.id);//"myBtn"
};
注意:這種方式添加的事件處理程序會在事件流的冒泡階段被處理。
- 可以刪除通過DOM0級方法指定的事件處理程序: btn.onclick=null; //刪除事件處理程序
如果使用的是HTML指定時間處理程序,那么onclick屬性的值就是一個包含著在同名HTML特性中指定的代碼的函數。將相應的屬性設為null,也可以刪除以這種方式指定的事件處理程序。
DOM2級事件處理程序
DOM2級事件定義了兩個方法,用于處理指定和刪除事件處理程序的操作:addEventListener()和removeEventListener()。所有DOM節點都包含這兩個方法,并且他們都接受3個參數。要處理的事件名、作為事件處理程序的函數和一個布爾值。布爾值中true表示在捕獲階段調用事件處理程序;false表示在冒泡階段調用事件處理程序。如果不是特別需要,不建議在事件捕獲階段注冊事件處理程序。
- 用DOM2級方法添加事件處理程序的好處是可以添加多個事件處理程序:
var btn=document.getElementById("myBtn");
btn.addEventListener("click",function(){
alert(this.id);
},false);
btn.addEventListener("click",function(){
alert("Hello world!");
},false);
這兩個事件處理程序會按照添加它們的順序觸發
- 通過addEventListener()添加的事件處理程序只能通過removeEventListener()方法移除。移除時傳入的參數與添加時傳入的參數要相同。這也意味著通過addEventListener()添加的匿名函數無法移除。
var btn=document.getElementById("myBtn");
btn.addEventListener("click",function(){
alert(this.id);
},false);
btn.removeEventListener("click",function(){
alert(this.id);
},false);//沒有用!看似傳入了相同的參數,其實這里的第二個參數與addEventListener()中的第二個參數是完全不同的函數
因此應該像下面這種寫法:
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(){ //是onclick,而非addEventListener()的click
alert(this.id);
});
- 在IE中使用attachEvent()與使用DOM0級方法的主要區別是事件處理程序的作用域。DOM0中是在元素的作用域內運行;在attachEvent()中是在全局作用域內運行,因此this=window。
1 var btn=document.getElementById("myBtn");
2 btn.attachEvent("onclick",function(){
3 alert(this===window); //true
4 });
- 與addEventListener()類似,attachEvent()也可以用來為一個元素添加多個事件處理程序。不同的是attachEvent()不是以添加事件的順序執行,而是以相反的順序執行。
- 同樣的用attachEvent()添加的事件如果是匿名函數則不能移除,否則可以用detachEvent()方法移除。
跨瀏覽器的事件處理程序
使用能力檢測來隔離瀏覽器的差異。要保證處理事件的代碼能在大多數瀏覽器下一致的運行,只需關注冒泡階段。
var EventUtil={
//視情況分別使用DOM0級方法、DOM2級方法、IE方法來添加/刪除事件,需要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:function(element,type,handler){
if(element.removeEventListener){
element.removeEventListener(type,handler,false);
} else if(element.detchaEvent){
element.detchaEvent("on"+type,handler);
} else{
element["on"+type]=null;
}
}
};
可以用像如下代碼這樣使用以上兩個方法:
var btn=document.getElementById("myBtn");
var handler=function(){
alert("Clicked");
};
EventUtil.addHandler(btn,click,handler);
//其他代碼
EventUtil.removeHandler(btn,click,handler);
addHandler()和removeHandler()沒有考慮到所有的瀏覽器問題,例如IE中的作用域問題。不過,使用它們添加和移除事件處理程序還是足夠了。此外還要注意,DOM0級對每個事件只支持一個事件處理。好在支持DOM0級的瀏覽器已經不多了。