<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Event Exam</title>
</head>
<body>
<div id="event" onclick="test()"></div>
</body>
</html>
一、事件流,三種事件流。
事件即用戶或?yàn)g覽器自身執(zhí)行的某種動作。
1.事件冒泡 IE中的事件流
click事件由近即遠(yuǎn) div--body--html--document

2.事件捕獲
document--html--body--div

3.DOM事件流
捕獲事件事件到body層就停止了,不會傳到div層,然后開始事件冒泡在傳回document。

IE9、Opera、Firefox、Chrome和Safari都支持DOM事件流;IE8及更早版本不支持DOM事件流。
二、事件處理程序
即響應(yīng)某個(gè)事件的函數(shù)就叫做事件處理程序。事件處理程序的名字以"on"開頭。
1.HTML事件處理程序
直接在html中綁定事件
<input type="button" value="Click Me" onclick="alert('Clicked')" />
這樣會創(chuàng)建一個(gè)封裝著元素屬性值的函數(shù),該函數(shù)中有一個(gè)局部變量event,也就是事件對象。
<!--輸出 click -->
<input type="button" value="Click Me" onclick="alert(event.type)" />
通過event變量,可以直接訪問事件對象,在這個(gè)函數(shù)內(nèi)部,this值等于事件的目標(biāo)元素。
<!--輸出 Click Me -->
<input type="button" value="Click Me" onclick="alert(this.value)" />
event 函數(shù)內(nèi)擴(kuò)展作用域的方式
可以輸出value
<input type="button" value="Click Me" onclick="alert(value)" />
<form method="post">
<input type="text" name="username" value="">
<input type="button" onclick="alert(username.value)">
</form>
缺點(diǎn):
存在一個(gè)時(shí)差問題。因?yàn)橛脩艨赡軙贖TML元素一出現(xiàn)在頁面上就觸發(fā)相應(yīng)的事件,但當(dāng)時(shí)的事件處理程序有可能尚不具備執(zhí)行條件。
這樣擴(kuò)展事件處理程序的作用域鏈在不同瀏覽器中會導(dǎo)致不同結(jié)果。不同JavaScript引擎遵循的標(biāo)識符解析規(guī)則略有差異,很可能會在訪問非限定對象成員時(shí)出錯(cuò)。
HTML與JavaScript代碼緊密耦合。
2.DOM0級事件處理程序
對每個(gè)事件只支持一個(gè)事件處理程序
var btn = document.getElementById("myBtn");
btn.onclick = function () {
alert(this.id);
}
//刪除點(diǎn)擊事件
btn.onclick = null;
<input type="button" value="Click Me" onclick="null" />
如果使用HTML指定事件處理程序,將相應(yīng)的屬性值設(shè)置為null,也可以刪除以這種方式指定的事件處理程序。
3.DOM2級事件處理程序
“DOM2級事件”定義了兩個(gè)方法,用于處理指定和刪除事件處理程序的操作:addEventListener()和removeEventListener()。所有DOM節(jié)點(diǎn)中都包含這兩個(gè)方法,并且它們都接受3個(gè)參數(shù):
- 1 事件名,
- 2 事件處理程序,
- 3 一個(gè)布爾值(true,表示在捕獲階段調(diào)用時(shí)間處理程序,false,表示在冒泡階段調(diào)用時(shí)間處理程序)
btn.addEventListener("click",function () {
alert(this.id);
},false)
btn.addEventListener("click",function () {
alert("hello World");
},false)
優(yōu)點(diǎn):使用DOM2可以添加多個(gè)事件處理程序,按添加方法的順序執(zhí)行。
移除點(diǎn)擊事件,需要將定義的事件提出來,移除的事件和添加的事件應(yīng)為同一個(gè)事件。
function handle() {
alert(this.id);
}
btn.addEventListener("click",handle,false)
btn.removeEventListener("click",handle,false)
大多數(shù)情況下,都是將事件處理程序添加到事件流的冒泡階段,這樣可以最大限度地兼容各種瀏覽器。最好只在需要在事件到達(dá)目標(biāo)之前截獲它的時(shí)候?qū)⑹录幚沓绦蛱砑拥讲东@階段。如果不是特別需要,我們不建議在事件捕獲階段注冊事件處理程序。
4.IE事件處理程序
IE中實(shí)現(xiàn)了與DOM中類似的方法,attachEvent()和detachEvent()。這兩個(gè)方法接受相同的兩個(gè)參數(shù):事件處理程序名稱與事件處理程序函數(shù)。由于IE8及更早版本只支持事件冒泡,所以通過attachEvent()添加的事件處理程序都被添加到冒泡階段。
var btn = document.getElementById("myBtn");
btn.attachEvent("onclick",function(){
alert(this==window);//true
})
在IE中使用attachEvent()和在DOM0級方法的主要區(qū)別
在于事件處理程序的作用域。attachEvent()的事件處理程序在全局中作用域運(yùn)行,在DOM0級方法的情況下,事件處理程序是局部的。
var btn = document.getElementById("myBtn");
btn.attachEvent("onclick",function(){
alert(this==window);//true
})
btn.attachEvent("onclick",function(){
alert("Hello World");
})
//與DOM方法不同的事,IE中不是按添加方法的順序執(zhí)行,而是相反的執(zhí)行,先輸出Hello World,在輸出true
attachEvent()添加的方法可以用detachEvent()方法移除,條件是必須提供相同的參數(shù),與DOM方法一致,不能刪除匿名函數(shù)。
支持IE事件處理程序的瀏覽器只有IE和Opera。
5.跨瀏覽器的事件處理程序
三、事件對象
1.DOM的事件處理對象
兼容DOM的瀏覽器會將一個(gè)event對象傳入到事件處理程序中。
var btn = document.getElementById("myBtn");
btn.onclick = function (event) {
alert("點(diǎn)我");
}


只有在事件處理程序執(zhí)行期間,event對象會存在,一旦時(shí)間處理程序執(zhí)行完,event對象就會被銷毀。
2.IE中的事件對象
使用DOM0級方法添加事件處理程序時(shí),event對象作為window對象的屬性存在。
使用attachEvent()添加的,就會有一個(gè)event對象作為參數(shù)被傳入事件處理函數(shù)。
3.跨瀏覽器的事件對象
四、事件類型
- UI(User Interface,用戶界面)事件,當(dāng)用戶與頁面上的元素交互時(shí)觸發(fā);
- 焦點(diǎn)事件,當(dāng)元素獲得或失去焦點(diǎn)時(shí)觸發(fā);
- 鼠標(biāo)事件,當(dāng)用戶通過鼠標(biāo)在頁面上執(zhí)行操作時(shí)觸發(fā);
- 滾輪事件,當(dāng)使用鼠標(biāo)滾輪(或類似設(shè)備)時(shí)觸發(fā);
- 文本事件,當(dāng)在文檔中輸入文本時(shí)觸發(fā);
- 鍵盤事件,當(dāng)用戶通過鍵盤在頁面上執(zhí)行操作時(shí)觸發(fā);
- 合成事件,當(dāng)為IME(Input Method Editor,輸入法編輯器)輸入字符時(shí)觸發(fā);
- 變動(mutation)事件,當(dāng)?shù)讓覦OM結(jié)構(gòu)發(fā)生變化時(shí)觸發(fā)。
1.UI事件 - load: 當(dāng)頁面完全加載后在window上面觸發(fā),當(dāng)所有框架都加載完畢時(shí)在框架集上面觸發(fā),當(dāng)圖像加載完畢時(shí)在<img>元素上面觸發(fā),或者當(dāng)嵌入的內(nèi)容加載完畢時(shí)在<object>元素上面觸發(fā)。
- unload:當(dāng)頁面完全卸載后在window上面觸發(fā),當(dāng)所有框架都卸載后在框架集上面觸發(fā),或者當(dāng)嵌入的內(nèi)容卸載完畢后在<object>元素上面觸發(fā)。
- abort:在用戶停止下載過程時(shí),如果嵌入的內(nèi)容沒有加載完,則在<object>元素上面觸發(fā)。
- error:當(dāng)發(fā)生JavaScript錯(cuò)誤時(shí)在window上面觸發(fā),當(dāng)無法加載圖像時(shí)在<img>元素上面觸發(fā),當(dāng)無法加載嵌入內(nèi)容時(shí)在<object>元素上面觸發(fā),或者當(dāng)有一或多個(gè)框架無法加載時(shí)在框架集上面觸發(fā)。
- select:當(dāng)用戶選擇文本框(<input>或<tex-terea>)中的一或多個(gè)字符時(shí)觸發(fā)。
- resize:當(dāng)窗口或框架的大小變化時(shí)在window或框架上面觸發(fā)。
- scroll:當(dāng)用戶滾動帶滾動條的元素中的內(nèi)容時(shí),在該元素上面觸發(fā)。<body>元素中包含所加載頁面的滾動條。
//load 事件 兩種添加方式,EventUtil為跨瀏覽器的事件對象。
在body元素上加onload="alert('hello')"事件,
EventUtil.addHandler(window, "load", function(event){
alert("Loaded!");
});
//unload 事件,用戶從一個(gè)頁面切換到另一個(gè)頁面觸發(fā)。
在body元素上加onunload="alert('hello')"事件,
EventUtil.addHandler(window, "unload", function(event){
alert("Loaded!");
});
//resize事件,當(dāng)瀏覽器被調(diào)整到一個(gè)新的高度或?qū)挾葧r(shí),會觸發(fā)。
EventUtil.addHandler(window, "resize", function(event){
var event = EventUtil.getEvent(event);
var pageX = event.pageX;
var pageY = event.pageY;
});
//scroll 事件
EventUtil.addHandler(window, "scroll", function(event){
alert("Loaded!");
});
2.焦點(diǎn)事件
- blur:在元素獲得焦點(diǎn)時(shí)觸發(fā)。這個(gè)事件不會冒泡,所有瀏覽器都支持。
- focus:在元素獲得焦點(diǎn)時(shí)觸發(fā)。這個(gè)事件不會冒泡;所有瀏覽器都支持它。
3.鼠標(biāo)事件和滾輪事件
DOM3級事件中定義了9個(gè)鼠標(biāo)事件:
- click:在用戶單擊主鼠標(biāo)按鈕(一般是左邊的按鈕)或者按下回車鍵時(shí)觸發(fā)。這一點(diǎn)對確保易訪問性很重要,意味著onclick事件處理程序既可以通過鍵盤也可以通過鼠標(biāo)執(zhí)行。
- dblclick:在用戶雙擊主鼠標(biāo)按鈕(一般是左邊的按鈕)時(shí)觸發(fā)。從技術(shù)上說,這個(gè)事件并不是DOM2級事件規(guī)范中規(guī)定的,但鑒于它得到了廣泛支持,所以DOM3級事件將其納入了標(biāo)準(zhǔn)。
- mousedown:在用戶按下了任意鼠標(biāo)按鈕時(shí)觸發(fā)。不能通過鍵盤觸發(fā)這個(gè)事件。
- mouseenter:在鼠標(biāo)光標(biāo)從元素外部首次移動到元素范圍之內(nèi)時(shí)觸發(fā)。這個(gè)事件不冒泡,而且在光標(biāo)移動到后代元素上不會觸發(fā)。DOM2級事件并沒有定義這個(gè)事件,但DOM3級事件將它納入了規(guī)范。IE、Firefox9+和Opera支持這個(gè)事件。
- mouseleave:在位于元素上方的鼠標(biāo)光標(biāo)移動到元素范圍之外時(shí)觸發(fā)。這個(gè)事件不冒泡,而且在光標(biāo)移動到后代元素上不會觸發(fā)。DOM2級事件并沒有定義這個(gè)事件,但DOM3級事件將它納入了規(guī)范。IE、Firefox9+和Opera支持這個(gè)事件。
- mousemove:當(dāng)鼠標(biāo)指針在元素內(nèi)部移動時(shí)重復(fù)地觸發(fā)。不能通過鍵盤觸發(fā)這個(gè)事件。
- mouseout:在鼠標(biāo)指針位于一個(gè)元素上方,然后用戶將其移入另一個(gè)元素時(shí)觸發(fā)。
- mouseover:在鼠標(biāo)指針位于一個(gè)元素外部,然后用戶將其首次移入另一個(gè)元素邊界之內(nèi)時(shí)觸發(fā)。不能通過鍵盤觸發(fā)這個(gè)事件。
- mouseup:在用戶釋放鼠標(biāo)按鈕時(shí)觸發(fā)。不能通過鍵盤觸發(fā)這個(gè)事件。
mouseleave,mouseenter不能冒泡
IE9之后的執(zhí)行順序,IE8及之前會跳過第二個(gè)mousedown和click事件
(1) mousedown
(2) mouseup
(3) click
(4) mousedown
(5) mouseup
(6) click
(7) dblclick
- 鍵盤與文本事件
- keydown:當(dāng)用戶按下鍵盤上的任意鍵時(shí)觸發(fā),而且如果按住不放的話,會重復(fù)觸發(fā)此事件。
- keypress:當(dāng)用戶按下鍵盤上的字符鍵時(shí)觸發(fā),而且如果按住不放的話,會重復(fù)觸發(fā)此事件。按下Esc鍵也會觸發(fā)這個(gè)事件。Safari 3.1之前的版本也會在用戶按下非字符鍵時(shí)觸發(fā)keypress事件。
- keyup:當(dāng)用戶釋放鍵盤上的鍵時(shí)觸發(fā)。
5.復(fù)合事件
IE9+支持。
6.變動事件
DOM2級的變動(mutation)事件能在DOM中的某一部分發(fā)生變化時(shí)給出提示。
- DOMSubtreeModified:在DOM結(jié)構(gòu)中發(fā)生任何變化時(shí)觸發(fā)。這個(gè)事件在其他任何事件觸發(fā)后都會觸發(fā)
- DOMNodeInserted:在一個(gè)節(jié)點(diǎn)作為子節(jié)點(diǎn)被插入到另一個(gè)節(jié)點(diǎn)中時(shí)觸發(fā)
- DOMNodeRemoved:在節(jié)點(diǎn)從其父節(jié)點(diǎn)中被移除時(shí)觸發(fā)。
- DOMNodeInsertedIntoDocument:在一個(gè)節(jié)點(diǎn)被直接插入文檔或通過子樹間接插入文檔之后觸發(fā)。這個(gè)事件在DOMNodeInserted之后觸發(fā)
- DOMNodeRemovedFromDocument:在一個(gè)節(jié)點(diǎn)被直接從文檔中移除或通過子樹間接從文檔中移除之前觸發(fā)。
- DOMAttrModified:在特性被修改之后觸發(fā)。
- DOMCharacterDataModified:在文本節(jié)點(diǎn)的值發(fā)生變化時(shí)觸發(fā)。
7.HTML5事件
- contextmenu事件
EventUtil.addHandler(window, "contextmenu", function(event){
var event = EventUtil.getEvent(event);
event.preventDefault();//禁用鼠標(biāo)默認(rèn)事件,比如右擊
});
- beforeunload事件
//需要鼠標(biāo)觸發(fā)window對象,即事件的對象。
EventUtil.addHandler(window, "beforeunload", function(event){
var event = EventUtil.getEvent(event);
var msg = "你確定要離開嗎?";
event.returnValue = msg; //事件的返回信息是給用戶的提示信息。
return msg;
});
- DOMContentLoaded事件
如前所述,window的load事件會在頁面中的一切都加載完畢時(shí)觸發(fā),但這個(gè)過程可能會因?yàn)橐虞d的外部資源過多而頗費(fèi)周折。而DOMCon-tentLoaded事件則在形成完整的DOM樹之后就會觸發(fā),不理會圖像、JavaScript文件、CSS文件或其他資源是否已經(jīng)下載完畢。 - readystatechange事件
提供與文檔或元素的加載狀態(tài)有關(guān)的信息 - pageshow和pagehide事件
第一個(gè)事件就是pageshow,這個(gè)事件在頁面顯示時(shí)觸發(fā),無論該頁面是否來自bfcache。在重新加載的頁面中,pageshow會在load事件觸發(fā)后觸發(fā);而對于bfcache中的頁面,pageshow會在頁面狀態(tài)完全恢復(fù)的那一刻觸發(fā)。另外要注意的是,雖然這個(gè)事件的目標(biāo)是document,但必須將其事件處理程序添加到window。 - hashchange事件
監(jiān)聽URL參數(shù)列表變化
8.設(shè)備事件
9.觸摸與手勢事件
五、內(nèi)存與性能
在javascript中,添加到頁面上的事件處理程序數(shù)量將直接關(guān)系到頁面的整體運(yùn)行性能。
原因:
每個(gè)函數(shù)都是對象,都會占用內(nèi)存。
內(nèi)存的對象越多,性能就越差。
事件委托
事件委托利用了事件冒泡,只指定一個(gè)事件,就能管理某一類型的所有事件。
var btn = document.getElementById("myBtn");
var handler = function(event){
switch(event.type){
case "click":
alert("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;
在使用事件時(shí),需要考慮如下一些內(nèi)存與性能方面的問題。
- 有必要限制一個(gè)頁面中事件處理程序的數(shù)量,數(shù)量太多會導(dǎo)致占用大量內(nèi)存,而且會讓用戶感覺頁面反應(yīng)不夠靈敏。
- 建立在事件冒泡機(jī)制之上的事件委托技術(shù),可以有效減少事件處理程序的數(shù)量。
- 建議在瀏覽器卸載頁面之前移除頁面中的所有事件處理程序。