JavaScript與HTML之間的交互是通過事件完成的。
可以使用事件偵聽器來預(yù)訂事件,正在傳統(tǒng)軟件工程中被稱為觀察員模式
觀察員模式支持頁面行為與外觀的松散耦合
ECMAScript因DOM而豐富多彩,因IE而煩的一筆
零、事件流
事件流描述的是從頁面中接收事件的順序,有趣的是,IE和Netscape居然采用了幾乎相反的事件流。IE為冒泡流,Netscape Communicator采用捕獲流(雖然現(xiàn)在很少使用),下面介紹下二者的定義,以及DOM標(biāo)準的事件流
- 冒泡流
事件流,即事件開始時由最具體的元素接收,然后逐層向上傳播到父節(jié)點(文檔),例如:
<div> => <body> => <html> => Document
下面列出冒泡流的圖示:
找不到圖,,, 算了算了
需要注意的是,IE5.5級更早版本的事件冒泡會跳過<html>元素,從<body>直接跳到document對象。
- 捕獲流
捕獲流與冒泡流相反,即先從不具體的對象出發(fā),逐漸定位至最具體的對象。
現(xiàn)在很少有人使用捕獲流,因此可以放心的使用冒泡流。
- DOM事件流
DOM事件流做出如下規(guī)定:
- “DOM2級事件”規(guī)定了事件流的三個階段:事件捕獲階段,處于目標(biāo)階段,事件冒泡階段。
- DOM事件流中,事件捕獲階段不會接收到事件,即在捕獲階段不涉及到目標(biāo)對象,下一個階段為處于目標(biāo)階段,因此事件處理可以看成冒泡流的一部分。
- 但是IE9、Safari、Chrome、Firefox、Opera9.5及更高版本在捕獲階段觸發(fā)事件對象上的事件。結(jié)果就是有兩個機會在目標(biāo)對象上觸發(fā)事件(DOM2方法中
addEventListener中的第三個參數(shù)true/false便可決定觸發(fā)事件發(fā)生在哪個階段)
一、事件監(jiān)聽器
事件處理程序又叫事件監(jiān)聽器,是響應(yīng)瀏覽器事件的函數(shù),事件監(jiān)聽器的名字以on開頭。
按類型分,大致可以分為:HTML事件處理程序、DOM0級事件處理程序、DOM2級事件處理程序、IE事件處理程序
HTML事件處理程序
通過與相應(yīng)事件處理程序同名的HTML特性來制定事件監(jiān)聽器的方法叫做HTML事件處理程序,其中,特性的值為相應(yīng)的HTML代碼。需要注意以下幾點:
- 鑲嵌在HTML中的JavaScript代碼不能使用未經(jīng)轉(zhuǎn)義的HTML語法字符,如
&``""``<``>。若要使用這些字符,需使用轉(zhuǎn)義字符。 - 事件處理程序中的代碼在執(zhí)行時,有權(quán)限訪問全局作用域中的任何代碼,且這個函數(shù)類似于使用with擴展作用域
- 在事件處理程序內(nèi)部,
this指向事件的目標(biāo)元素 - 允許跨表單字段訪問,無需引用表單元素就能訪問其他表單字段
- 由于時差,作用域鏈,緊密耦合的原因,最好減少使用
DOM0事件處理程序
方式:將一個函數(shù)賦值給一個元素(或?qū)ο螅┑氖录幚沓绦驅(qū)傩裕⑶沂录幚沓绦蚴窃谠氐淖饔糜蛑羞M行的。
element.onkeydown = function(){}
- 以DOM0級事件處理程序會在事件流的冒泡流中進行
- 刪除通過DOM0級方法制定的事件處理程序的方法
element.onclick = null;
DOM2級事件處理程序
DOM2級定義了兩個方法addEventListener()和removeEventListener(),接收三個參數(shù):要處理的事件名,作為事件處理程序的函數(shù),在捕獲階段調(diào)用事件處理程序(true)還是在冒泡階段調(diào)用事件處理程序(false)
element.addEventListener('click',function(){},false)
- DOM2級方法添加事件處理程序的運行順序是按照添加順序的
- 匿名函數(shù)無法被`removeEventListener·移除
- 一般都是講布爾值設(shè)置為
false,這樣可最大限度兼容各種瀏覽器
IE事件處理程序
關(guān)于IE事件處理程序,這里主要講下與DOM級事件處理成序的區(qū)別
element.attachEvent('onclick',function(){}) //事件名稱+on
- 包含兩個方法:
attachEvent,detachEvent,接受兩個參數(shù):事件處理程序名稱,事件處理程序函數(shù),此處事件處理程序名稱要加on。注意,IE8級更早版本只支持冒泡流 - 使用IE方法時,函數(shù)作用域為全局作用域,this指向window
- IE方法添加的事件處理程序以相反的順序被觸發(fā)(與DOM相反)
二、事件對象
注意區(qū)分JavaScript中最重要的兩個對象:目標(biāo)對象和事件對象,目標(biāo)對象對應(yīng)于事件流中的被觸發(fā)的目標(biāo)元素或文檔,事件對象對應(yīng)于觸發(fā)事件時傳入事件監(jiān)聽器的參數(shù)。事件對象包含著所有與事件有關(guān)的信息,包括事件的目標(biāo)元素,事件的類型及其他與特定事件相關(guān)的信息。
DOM事件對象
兼容DOM的瀏覽器會將一個event對象傳入事件處理程序
element.onkeydown=function(event){
alert(event.type)}
利用event對象可以實現(xiàn)許多功能,如通過一個函數(shù)處理多個事件,防止事件默認行為,防止觸發(fā)連帶事件處理程序。具體見《JavaScript高級程序設(shè)計》
IE事件對象
IE中同樣存在event對象,不過對象有幾種存在的方式,如何調(diào)用取決于事件處理程序的類型:
- DOM0級方法中,event對象作為window對象的一個屬性
- IE事件程序中,event既可直接調(diào)用,也可使用window對象訪問。
三、跨瀏覽器兼容
為了解決跨瀏覽器兼容問題,大家可以使用能夠隔離瀏覽器差異的JavaScript庫,也可以利用能力檢測自己制作一個兼容腳本
下面是兼容的腳本
var EventUtil={
addHandler: function(element,type,handler){
if(element.addEventListener){
element.addEventListener(type,handler,false)
}else if(element.attachElement){
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.detachEvent){
element.detachEvent('on'+type,handler)
}else{
element['on'+type]=null;
}
},//移除事件處理程序
getEvent: function(event){
return event?event:window.event;
},//獲取事件對象
getTarget: function(event){
return event.target || event.srcElement;
},//獲取目標(biāo)對象
preventDefault: function(event){
if(event.preventDefault()){
event.preventDefault()
}else{
event.returnValue = null;
}
},//防止事件默認行為
stopPropagation: function(event){
if(event.stopPropagation){
event.stopPropagation()
}else {
event.cancelBubble;
}
}
};
四、事件類型
DOM3級事件規(guī)定了以下事件:
- UI事件:當(dāng)用戶與頁面上的元素交互時觸發(fā)
- 鼠標(biāo)事件: 當(dāng)用戶通過鼠標(biāo)在頁面上執(zhí)行操作時觸發(fā)
- 滾輪事件:當(dāng)使用鼠標(biāo)滾輪(或類似設(shè)備時觸發(fā))
- 文本事件: 擋在文檔中輸入文本時觸發(fā)
- 鍵盤事件
- 合成事件:當(dāng)為IME(Input Method Editor,輸入法編輯器)輸入字符時觸發(fā)
- 變動事件: 當(dāng)?shù)讓覦OM結(jié)構(gòu)發(fā)生變化時觸發(fā)