JavaScript與HTML之間的交互是通過事件實現的。事件是指文檔或瀏覽器窗口發生的一些特定的交互瞬間,可以用監聽器(或處理程序)來預定事件,以便在事件發生時執行相應的代碼。——摘自《高程》
理解事件是實現良好交互的必要條件,本文旨在系統地總結事件相關知識。
(上)主要內容:
- 理解事件流
使用事件處理程序
1.理解事件流
事件流描述的是從頁面中接收事件的順序。
首先你應該明白存在兩種完全相反的事件流概念。一個是自下而上的事件冒泡流(IE提出),另一個是自上而下的事件捕獲流(Netscape提出)。
圖爲“DOM2級事件”規定的事件流,它包括三個過程:事件捕獲階段、處於目標階段和事件冒泡階段。
在DOM事件流中,實際的目標在捕獲階段不會接收到事件,捕獲階段到<body>
就停止了,下一階段是目標階段,事件在<div>
上發生,並在事件處理中被看做是冒泡階段的一部分(所以,是否取消冒泡與事件的發生有密切聯繫)
但是,實際上,多數支持DOM事件的瀏覽器(IE9+,Safari,chrome、Firefox和Opera9.5+)都會在捕獲階段觸發事件對象上的事件,因此,就有兩個機會在目標對象上操作事件啦。
2.事件處理程序
事件處理程序綁定方法主要有兩種:在HTML標籤中和在JavaScript腳本中。
在HTML標籤中綁定事件有兩種方法:
1.純HTML
<input type="button" value="Click me" onclick="alert('Clicked')">
這種方法注意不能在其中使用未經轉義的html語法字符——(& “”< >)
2.HTML+函數
<input type="button" value="Click me" onclick="showMessage()">
即使showMessage()函數是外部文件的也可以,事件處理程序代碼在執行時有權訪問全局作用域中任何代碼。
一般不建議在HTML中添加事件處理,因爲綁定的this指向全局作用域。
在腳本中添加的事件處理程序分爲三種:DOM0級、DOM2級和IE
1.DOM0級事件處理的創建與刪除
var btn=document.getElementById("myBtn");
btn.onclick=function(){
alert(this.id); //"myBtn"
}
btn.onclick=null;
使用DOM0級事件處理程序被認爲是元素的方法,注意例中的this,以這種方法添加的事件是在元素的作用域中運行的,且在事件冒泡階段被處理。
這種方法同一個事件只能添加一個事件處理程序。
2.DOM2級事件處理程序的創建與刪除
var btn=document.getElementById("myBtn");
var handler=function(){
alert(this.id);
};
btn.addEventListener("click",handler,false);
btn.addEventListener("click",function(){
alert("Hello Cici!");
},false);
btn.removeEventListener("click",handler,false);
addEventListener()和removeEventListener()接受三個參數:要處理的事件名、作爲事件處理的函數和一個布爾值(默認爲false,true表示在捕獲階段調用事件處理函數,false表示在冒泡階段調用事件處理函數)。
注意,如果想用removeEventListener()移除事件,一定要保證三個參數與添加事件時完全一致,所以addEventListener()添加的匿名函數是無法被移除的,如上例中給“click”添加的第二個事件處理程序。
使用DOM2級最大的好處是可以添加多個事件處理程序,他們會按照添加的順序觸發。
3.IE事件處理程序的創建與刪除
var btn=document.getElementById("myBtn");
var handler=function(){
alert("Hi Cici~");
};
btn.attachEvent("onclick",handler);
btn.attachEvent("onclick",function(){
alert("Best Cici!");
});
btn.detachEvent("onclick",handler);
IE8及更早版本只支持事件冒泡,attachEvent()和detachEvent()接受兩個參數,事件處理程序名稱和函數。注意第一個參數與DOM不同,需要加”on”。
IE中使用attachEvent()與DOM2級事件處理程序的相同之處是,不能移除添加的是匿名函數的事件處理函數。
他們的主要區別在於事件處理程序的作用域。這一點在寫跨瀏覽器的代碼時肥腸重要!!!在使用attachEvent()方法的情況下,事件處理程序會在全局作用域運行,也就是說,此時this===window
。
還有一點不同就是,attachEvent()也可以添加多次事件處理程序,但是觸發順序與添加順序相反。
知道了以上知識,我們可以着手寫一個跨瀏覽器的事件處理程序了。
var EventUtil = {
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.dtachEvent){
element.dtachEvent("on"+type,handler);
}else{
element["on"+type]=null;
}
},
}