一、基本概念
1、事件冒泡
IE的事件流叫做事件冒泡,即事件開始時由最具體的元素接收,然後逐級向上傳播到較爲不具體的節點(文檔)。
2、事件捕獲
Netscape Communicator團隊提出的另一種事件流叫做事件捕獲。事件捕獲的思想是不太具體的節點應該更早接收到事件,而最具體的節點應該最後接收到事件。事件捕獲的用意在於在事件到達預定目標之前捕獲它。
3、DOM事件流
“DOM2級事件”規定的事件流包括三個階段:事件捕獲階段、處於目標階段和事件冒泡階段。
二、事件處理程序
1、HTML事件處理程序
<input type="button" value="Click me" onclick="alert('Clicked')"/>
在HTML中定義的事件處理程序可以包含要執行的具體動作,也可以調用在頁面其他地方定義的腳本
<script type="text/javascript">
function showMessage(){
alert("Hello world");
}
<script/>
<input type="button" value="Click Me" onclick="showMessage()"/>
事件處理程序中的代碼在執行時,有權訪問全局作用域中的任何代碼。
2、DOM0級事件處理程序
通過JavaScript指定事件處理程序的傳統方式,就是將一個函數賦值給一個事件處理程序。
var btn=document.getElementById("myBtn");
btn.onclick=function(){
alert(this.id); //"myBtn"
};
btn.onclick=null; //刪除事件處理程序
這時候的事件處理程序是在元素的作用域中運行,所以會返回myBtn。
3、DOM2級事件處理程序
“DOM2級事件”定義了兩個方法,用於處理指定和刪除事件處理程序的操作:addEventListener()和removeEventListener()。
所有DOM節點中都包含這兩個方法,並且它們都接受3個參數:要處理的事件名、作爲事件處理程序的函數和一個布爾值。
最後這個布爾值參數如果是true,表示在捕獲階段調用事件處理程序;如果是false,表示在冒泡階段調用事件處理程序。
var btn=document.getElementById("mybtn");
btn.addEventListener("click",function(){
alert(this.id);
},false);
btn.addEventListener("click",function(){
alert("Hello world");
},false);
這裏添加的事件處理程序也是在其依附的元素的作用域中運行。使用DOM2級方法添加事件處理程序的主要好處是可以添加多個事件處理程序。這兩個事件處理程序會按照添加它們的順序觸發。
通過addEventListener()添加的事件處理程序只能使用removeEventListener()來移除;移除時傳入的參數與添加處理程序時使用的參數相同。這也意味着通過addEventListener()添加的匿名函數將無法移除。
var btn=document.getElementById("myBtn");
btn.addEventListener("click",function(){
alert(this.id);
},false);
//這裏省略了其他代碼
btn.removeListener("click",function(){ //沒有用!
alert(this.id);
},false);
var btn=document.getElementById("myBtn");
var handler=function(){
alert(this.id);
};
btn.addEventListener("click",handler,false);
//這裏省略了其他代碼
btn.removeListener("click",handler,false); //有效
4、IE事件處理程序
attachEvent()和detachEvent(),只接受兩個參數。通過attachEvent()添加的事件處理程序都會被添加到冒泡階段。
在使用attachEvent()方法的情況下,事件處理程序會在全局作用域中運行,因此this等於window.
var btn=document.getElementById("myBtn");
btn.attachEvent("onclick",function(){
alert(this===window); //true
});
var btn=document.getElementById("myBtn");
btn.attachEvent("onclick",function(){
alert("Clicked"); //該事件後觸發
});
btn.attachEvent("onclick",function(){
alert("Hello world!"); //該事件先觸發
});
移除事件:
var btn=document.getElementById("myBtn");
var handler=function(){
alert("Clicked");
};
btn.attachEvent("onclick",handler);
//這裏省略了其他代碼
btn.detachEvent("onclick",handler);
5、跨瀏覽器的事件處理程序
var EventUtil={
addHandler:function(element,type,handler){
if(element.addEventListener){
element.addEventListerner(type,handler,false);
}else if(element.attachEvent){
element.attachEvent("on"+type,handler);
}else{
element["on"+type]=handler;
}
},
removerHandler: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;
}
}
};
可以像下面這樣使用EventUtil對象:
var btn=document.getElementById("myBtn");
var handler=function(){
alert("Clicked");
};
EventUtil.addHandler(btn,"click",handler);
//這裏省略了其他代碼
EventUtil.removeHandler(btn,"click",handler);
三、事件對象
1、DOM中的事件對象
兼容DOM的瀏覽器會將一個event對象傳入到事件處理程序中。無論指定事件處理程序時使用什麼方法(DOM0級或DOM2級),都會傳入event對象。
2、IE中的事件對象
與訪問DOM中的event對象不同,要訪問IE中的event對象有幾種不同的方式,取決於指定事件處理程序的方法。在使用DOM0級方法添加事件處理程序時,event對象作爲window對象的一個屬性存在。
3、跨瀏覽器的事件對象
IE中的event對象的全部信息和方法DOM對象中都有,只不過實現方式不一樣。
var EventUtil={
addHandler:function(element,type,handler){
//省略的代碼
},
getEvent:function(event){
return event?event:window.event;
},
getTarget:function(event){
return event.target||event.srcElement;
},
preventDefault:function(event){
if(event.preventDefault){
event.preventDefault();
}else{
event.returnValue=false;
}
},
removeHandler:function(element,type,handler){
//省略的代碼
},
stopPropagation:function(event){
if(event.stopPropagation){
event.stopPropagation();
}else{
event.cancelBubble=true;
}
}
};
1、使用第一個方法:
btn.onclick=function(event){
event=EventUtil.getEvent(event);
};
2、使用第二個方法:
btn.onclick=function(event){
event=EventUtil.getEvent(event);
var target=EventUtil.getTarget(event);
};
3、使用第三個方法:
var link=document.getElementById("myLink");
link.onclick=function(event){
event=EventUtil.getEvent(event);
EventUtil.preventDefault(event);
};
4、使用第四個方法:
var btn=document.getElementById("myBtn");
btn.onclick=function(event){
alert("Clicked");
event=EventUtil.getEvent(event);
EventUtil.syopPropagation(event);
};
document.body.onclick=function(event){
alert("Body clicked");
};
四、事件委託
對“事件處理程序過多”問題的解決方案就是事件委託。事件委託利用了事件冒泡,只指定一個事件處理程序,就可以管理某一類型的所有事件。以下面的HTML代碼爲例:
<ul>
<li id="goSomewhere">Go somewhere</li>
<li id="doSomething">Do something</li>
<li id="sayHi">Say hi</li>
</ul>
使用事件委託,只需要在DOM樹中儘量最高的層次上添加一個事件處理程序,如下面的例子所示:
var list=document.getElementById("myLinks");
EventUtil.addHandler(list,"click",function(event){
event=EventUtil.getEvent(event);
var target=EventUtil.getTarget(event);
switch(target.id){
case "doSomething":
document.title="I changed the document's title";
break;
case "goSomewhere":
location.href="http://www.wrox.com";
break;
case "sayHi":
alert("hi");
break;
}
});