事件流
事件流描述的是從頁(yè)面中接受事件的順序稚虎。但是IE和Netscape開(kāi)發(fā)團(tuán)隊(duì)提出了差不多相反的事件流的概念白嘁。IE的事件流是事件冒泡但惶,而Netescape Communicator的事件流是事件捕獲枷遂。
- 事件冒泡
IE的事件流叫做事件冒泡澈灼,即事件開(kāi)始時(shí)由最具體的元素(文檔中嵌套層次最深的那個(gè)節(jié)點(diǎn))接收,然后逐級(jí)向上傳播到較為不具體的節(jié)點(diǎn)店溢。
- 事件捕獲
事件捕獲的思想是不太具體的節(jié)點(diǎn)應(yīng)該更早接受到事件叁熔,而最具體的節(jié)點(diǎn)應(yīng)該最后接收到事件。事件捕獲的泳衣在于事件到達(dá)預(yù)定目標(biāo)前捕獲它床牧。
但是由于老版本不支持荣回,因此很少有人用事件捕獲,在特殊時(shí)候再利用事件捕獲戈咳,一般都可以利用事件冒泡心软。
- DOM事件流
"DOM2級(jí)事件"規(guī)定的事件流包括了三個(gè)階段:事件捕獲階段、處于目標(biāo)階段和事件冒泡階段著蛙。首先發(fā)生的是事件捕獲删铃,為截獲事件提供了機(jī)會(huì)。然后是世紀(jì)的目標(biāo)接收到事件踏堡。最后一個(gè)階段是冒泡階段猎唁,可以在這個(gè)階段對(duì)事件做出響應(yīng)。
在DOM的事件流中顷蟆,實(shí)際的目標(biāo)在捕獲階段不會(huì)接收到事件诫隅。下一個(gè)階段是處于目標(biāo)階段,于是事件在目標(biāo)上發(fā)生帐偎,并且在事件處理中看作是冒泡階段的一部分逐纬。然后冒泡階段發(fā)生,事件又傳播回文檔削樊。
事件處理程序
事件處理就是用戶或者瀏覽器自身執(zhí)行的某種動(dòng)作豁生。例如click、load和mouseover等漫贞,都是事件的名字沛硅。而響應(yīng)某個(gè)事件的函數(shù)就叫做事件處理程序,也叫做事件偵聽(tīng)器绕辖。
為事件指定的處理程序有如下幾種:
- HTML事件處理程序
某個(gè)元素支持的每種事件摇肌,都可以使用一個(gè)與相應(yīng)事件處理程序同名的HTML特性來(lái)指定的。這個(gè)特性的值應(yīng)該是能夠執(zhí)行JavaScript代碼仪际。
- DOM0級(jí)事件處理程序
通過(guò)JavaScript指定事件處理程序的傳統(tǒng)方式围小,就是將一個(gè)函數(shù)賦值給一個(gè)事件處理程序?qū)傩躁侵琛_@種為事件處理程序賦值的方法是在第四代Web瀏覽器中出現(xiàn)的,而且至今仍然為所有現(xiàn)代瀏覽器所支持肯适。要使用JavaScript指定事件處理程序变秦,首先必須取得一個(gè)要操作的對(duì)象的引用。
- DOM2級(jí)事件處理程序
"DOM2"事件定義了兩個(gè)方法框舔,用于處理指定和刪除事件處理程序的操作:addeventListener()和removeEventListener()蹦玫。所有DOM節(jié)點(diǎn)中都包含這兩個(gè)方法,并且它們都接受3個(gè)參數(shù):要處理的事件名刘绣、作為事件處理程序的函數(shù)和一個(gè)布爾值樱溉。如果最后這個(gè)布爾值參數(shù)是true,表示在捕獲階段調(diào)用事件處理程序纬凤;如果是false福贞,表示在冒泡階段調(diào)用事件處理程序。
比如要在按鈕上為click事件添加事件處理程序停士,可以使用以下代碼:
var btn = document.getElementById("myBtn");
btn.addEventListener("click", function(){
console.log(this.id);
}, false);
此事件會(huì)在冒泡階段被觸發(fā)挖帘,此時(shí)和DOM0級(jí)方法一樣,這里添加的事件處理程序也是其依附的元素的作用域中運(yùn)行恋技。使用DOM2級(jí)添加方法的主要好處是能夠添加多個(gè)事件處理程序拇舀。
- IE事件處理程序
IE實(shí)現(xiàn)了和DOM類(lèi)似的兩個(gè)方法,attachEvent()和detachEvent()蜻底。這兩個(gè)方法接受相同的兩個(gè)參數(shù):事件處理程序名稱和事件處理程序函數(shù)你稚。由于IE8以及更早的版本只支持事件冒泡,所以通過(guò)attachEvent()添加的事件處理程序都會(huì)被添加到冒泡階段朱躺。
在IE中使用attachEvent()與使用DOM0級(jí)方法的主要區(qū)別在于事件處理程序的作用域刁赖。在使用DOM0級(jí)方法的時(shí)候,事件處理程序會(huì)在其所屬元素的作用域內(nèi)運(yùn)行长搀;在使用attachEvent()方法時(shí)候宇弛,作用域?yàn)槿肿饔糜颍虼藅his等于window源请,例如:
var btn = document.getElementById("myBtn");
btn.attachEvent("onclick", function(){
console.log(this === window) // true
})
同時(shí)與addEventListener()類(lèi)似枪芒,也可以為一個(gè)元素添加多個(gè)事件處理程序。
- 跨瀏覽器的事件處理程序
為了跨瀏覽器的方式處理事件谁尸,不少開(kāi)發(fā)人員會(huì)使用能夠隔離瀏覽器差異的JavaScript庫(kù)舅踪。要保證處理事件的代碼能在大多數(shù)瀏覽器下一致運(yùn)行,只需要關(guān)注冒泡階段良蛮。
第一個(gè)要?jiǎng)?chuàng)建的方法是addHandler()抽碌,作用是根據(jù)情況分別使用DOM0級(jí)方法、DOM2級(jí)方法或者IE方法來(lái)添加事件决瞳。這個(gè)函數(shù)接受3個(gè)參數(shù):要操作的元素货徙、事件名稱和事件處理程序函數(shù)左权。與之相對(duì)應(yīng)的是removeHandler(),也接受相同的參數(shù)痴颊。
事件對(duì)象
在觸發(fā)DOM上的某個(gè)事件時(shí)候赏迟,會(huì)產(chǎn)生一個(gè)事件對(duì)象event,這個(gè)對(duì)象中包含著所有與事件有關(guān)的信息蠢棱。包括導(dǎo)致事件的元素锌杀、事件的類(lèi)型以及其他與特定事件相關(guān)的信息。所有瀏覽器都支持event對(duì)象泻仙,但是支持方式不同糕再。
- DOM中的事件對(duì)象
兼容DOM的瀏覽器會(huì)將一個(gè)event對(duì)象傳入到事件處理程序中。無(wú)論指定事件處理程序時(shí)使用什么方法(DOM0級(jí)或DOM2級(jí))饰豺,都會(huì)傳入event對(duì)象。
例如
var btn = document.getElementById("myBtn");
btn.onclick = function(event){
console.log(event.type); // "click"
};
btn.addEventListener("click", function(){
console.log(event.type); // "click"
}, false);
這兩個(gè)例子都會(huì)顯示事件的類(lèi)型允蜈,這個(gè)屬性始終都會(huì)包含被觸發(fā)的事件類(lèi)型冤吨。
在通過(guò)html特性指定事件處理程序時(shí),變量event中保存著event對(duì)象饶套,比如
<input type = "button" value = "Click me" onclick = "alert(event.type)" />
這種方式提供event對(duì)象漩蟆,可以讓html特性事件處理程序與javascript函數(shù)執(zhí)行相同的操作
在事件處理程序內(nèi)部,對(duì)象this始終等于currentTarget的值妓蛮,而target則只包含事件的實(shí)際目標(biāo)怠李。如果直接將事件處理程序指定給了目標(biāo)元素,則this蛤克、currentTarget和target包含相同的值捺癞。比如
var btn = document.getElementById("myBtn");
btn.onclick = function(event){
console.log(event.currentTarget === this); //true
console.log(event.target === this); //true
};
這個(gè)例子檢驗(yàn)了currentTarget和target與this的值,由于click事件的目標(biāo)是按鈕构挤,因此這三個(gè)值是相等髓介。如果事件處理程序存在與按鈕的父節(jié)點(diǎn)中(例如document,body中)那么這些值是不相等的筋现。如下例子
document.body.onclick = function(event){
console.log(event.currentTarget === document.body); //true
console.log(this === document.body); //true
console.log(event.target === document.getElementById("myBtn")); //true
}
當(dāng)單擊這個(gè)例子中的按鈕時(shí)候唐础,this和currentTarget都等于document.body,因?yàn)槭录幚淼某绦蚴亲?cè)到這個(gè)元素上的矾飞,但是target的元素卻等于按鈕元素一膨,是因?yàn)樗莄lick的真正目標(biāo)。
在需要通過(guò)一個(gè)函數(shù)處理多個(gè)事件的時(shí)候洒沦,可以使用type屬性豹绪。例如
var btn = document.getElementById("myBtn");
var handler = function(event){
switch(event.type){
case "click":
console.log("Clicked");
break;
case "mouseover":
event.target.style.backgroundColor = "red";
break;
case "mouseout":
event.target.style.backgroundColor = "";
break;
}
};
btn.onclick = handler;
btn.onmouseover = handler;
btn.onmouseout = handler;
利用handler函數(shù)來(lái)處理3中不同的事件。這里可以通過(guò)檢測(cè)event.type屬性申眼,讓函數(shù)能夠確定發(fā)生了什么事件森篷,并且執(zhí)行相應(yīng)操作输钩。
要阻止特定事件默認(rèn)行為,可以使用preventDefault()方法仲智。但是只有cancelable屬性設(shè)置為true的事件买乃,才可以使用preventDefault()來(lái)取消默認(rèn)行為。
stopPropagation()方法用于立即停止事件在DOM層次中的傳遞钓辆,進(jìn)一步取消事件的捕獲或者冒泡剪验。同時(shí),事件對(duì)象的eventPhase屬性可以確定事件在當(dāng)前位置前联。
- IE中的事件對(duì)象
與訪問(wèn)DOM中的event對(duì)象不同功戚,要訪問(wèn)IE中的event對(duì)象有幾種不同的方式,取決于指定事件處理程序的方法似嗤。在使用DOM0級(jí)方法添加事件處理程序時(shí)候啸臀,event作為window對(duì)象的一個(gè)屬性存在。
var btn = document.getElementById("myBtn");
btn.onclick = function(){
var event = window.event;
console.log(event.type); //"click"
}
此時(shí)烁落,在通過(guò)window.event取得了event對(duì)象乘粒,并且檢測(cè)了被觸發(fā)事件的類(lèi)型∩怂可是如果事件處理程序利用的是attachEvent()添加的灯萍,那么就會(huì)有一個(gè)event對(duì)象作為參數(shù)被傳入事件處理程序函數(shù)中。
var btn = document.getElementById("myBtn");
btn.attachEvent("onclick", function(event){
console.log(event.type); //"click"
});
在類(lèi)似使用這樣的方法每聪,可以通過(guò)window對(duì)象來(lái)訪問(wèn)event對(duì)象旦棉,就像使用DOM0方法一樣。
由于事件處理程序的作用域是根據(jù)指定它的方式來(lái)確定的药薯,所以不能認(rèn)為this會(huì)始終等于事件目標(biāo)绑洛。比如
var btn = document.getElementById("myBtn");
btn.onclick = function(){
console.log(window.event.srcElement === this); //true
}
btn.attachEvent("onclick", function(){
console.log(event.srcElement === this ); //false
});
第一個(gè)事件處理程序中(使用DOM0級(jí)方法指定的)srcElement屬性等于this,但是第二個(gè)事件處理程序中童本,這二者值并不相同
- 跨瀏覽器中的事件對(duì)象
IE中event對(duì)象的全部信息和方法DOM中都有诊笤,只不過(guò)實(shí)現(xiàn)方式不一樣。不過(guò)可以基于其相似性巾陕,可以寫(xiě)出跨瀏覽器的事件對(duì)象方案讨跟。
function getEvent(e) {
return e || window.event;
}
function getTarget(e) {
return e.target || e.scrElement;
}
function preventDefault(e) {
if (e.preventDefault)
e.preventDefault();
else
e.returnValue = false;
}
function stopPropagation(e) {
if (e.stopPropagation)
e.stopPropagation();
else
e.cancelBubble = true;
}
常用的HTML事件
load:當(dāng)頁(yè)面完全加載后在window上觸發(fā),當(dāng)圖像加載完成后在img元素上觸發(fā)鄙煤,或當(dāng)嵌入內(nèi)容加載完成時(shí)晾匠,在object元素上觸發(fā)
unload:頁(yè)面完全卸載后在window上觸發(fā),或嵌入內(nèi)容卸載后在object元素觸發(fā)
select:用戶選擇文本框中的字符時(shí)觸發(fā)
change:文本框焦點(diǎn)變化后其值改變時(shí)觸發(fā)
submit:用戶提交表單的時(shí)候觸發(fā)
resize:窗口或框架大小變化的時(shí)候在window上觸發(fā)
scroll:用戶滾動(dòng)帶滾動(dòng)條的元素時(shí)梯刚,在該元素上觸發(fā)
focus:頁(yè)面或元素獲得焦點(diǎn)時(shí)在window及相應(yīng)元素上觸發(fā)
blur:頁(yè)面或元素失去焦點(diǎn)時(shí)在window及相應(yīng)元素上觸發(fā)
beforeunload:頁(yè)面卸載前在window上觸發(fā)
mousewheel:不算HTML的凉馆,當(dāng)用戶通過(guò)鼠標(biāo)滾輪與頁(yè)面交互,在垂直方向滾動(dòng)頁(yè)面時(shí)觸發(fā)