13.1 事件流
“DOM2級事件”規(guī)定事件流包括3個階段:事件捕獲階段,處于目標(biāo)階段谜喊,事件冒泡階段。
事件捕獲表示從最外層節(jié)點開始捕獲事件倦始,然后逐級像內(nèi)傳播直到具體節(jié)點。
事件冒泡表示事件由最具體元素開始接受元素鞋邑,然后逐級向上傳播到文檔節(jié)點账蓉。
13.2 事件處理程序
13.2.1 DOM2級事件處理程序
“DOM2級事件”為所有DOM節(jié)點定義了addEventListener()和removeEventListener()兩個方法逾一,分別用于指定事件處理程序和移除事件處理程序。都接收3個參數(shù):事件名稱嬉荆、事件處理程序、一個布爾值鄙早,布爾值為true,則在捕獲階段調(diào)用事件處理程序限番,布爾值為false舱污,則在冒泡階段調(diào)用事件處理程序扩灯。
使用DOM2級事件處理程序可以為同一個事件添加多個程序,會按照添加的順序觸發(fā)霜瘪。addEventListener()添加的事件處理程序只能用removeEventListener()來移除,移除時傳入的參數(shù)與添加時的相同颖对,無法刪除匿名函數(shù),因為兩個一樣的匿名函數(shù)并不是同一個函數(shù)缤底。
13.2.2 IE事件處理程序
IE使用attachEvent()和detachEvent(),都接收兩個參數(shù)个唧,事件名稱和事件處理程序,只在冒泡階段觸發(fā)徙歼。事件名稱需要添加“on”前綴,同一事件多個程序會按添加的相反順序觸發(fā)鲁沥。
13.3 事件對象
在DOM上觸發(fā)事件時,會產(chǎn)生一個event事件對象画恰。這個對象中包含著所有與事件有關(guān)的信息。
13.3.1 DOM中的事件對象
兼容DOM的瀏覽器會將一個event對象傳入事件處理程序中允扇,event對象所有屬性:
bubble则奥,布爾值,只讀狭园,表示事件是否冒泡;
cancelable唱矛,布爾值,只讀绎谦,表示是否可以取消事件默認行為;
currentTarget窃肠,節(jié)點,只讀冤留,當(dāng)前正在處理時間的元素,在事件處理程序內(nèi)部總是等于this值纤怒;
defaultPrevented糯而,布爾值歧蒋,只讀,為true表示已經(jīng)調(diào)用了preventDefault()方法州既;
detail吴叶,數(shù)值信息,只讀序臂,事件相關(guān)細節(jié)信息;
eventPhase奥秆,數(shù)值信息,只讀构订,表示調(diào)用事件處理程序的階段,1表示捕獲悼瘾,2表示“處于目標(biāo)”审胸,3表示冒泡;
preventDefault()砂沛,方法,取消事件的默認行為碍庵,cancelable為true時才可以使用;
stopImmediatePropagation()悟狱,方法,取消事件進一步冒泡芽淡,同時阻止任何事件處理程序被調(diào)用;
stopPropagation()挣菲,方法,取消事件的進一步冒泡白胀,bubble為true時才可以使用;
target或杠,節(jié)點,事件的實際目標(biāo)向抢;
trusted,布爾值挟鸠,只讀叉信,為true表示事件是由瀏覽器生成的硼身,為false表示事件由JavaScript添加;
type覆享,字符串,觸發(fā)的事件類型撒顿;
view,事件發(fā)生的window對象。
13.3.2 IE中的事件對象
使用DOM0級添加事件處理程序時啸驯,event對象是window的一個屬性,使用attachEvent()時祟峦,event可以通過window對象訪問,也會作為參數(shù)傳入事件處理程序宅楞。IE事件對象屬性:
cancelBubble,布爾值厌衙,默認為false,設(shè)置為true就可以取消事件冒泡婶希;
returnValue,布爾值喻杈,默認為true,設(shè)置為false可以取消事件默認行為筒饰;
srcElement缴啡,節(jié)點业栅,事件的實際目標(biāo);
type谬晕,字符串,事件的名稱攒钳。
13.3.3 跨瀏覽器的事件模型
var EventUtil = {
// 添加事件
addHandler: function (ele, type, handler) {
if(ele.addEventListener){
ele.addEventListener(type,handler,false);
}else if(ele.attachEvent){
ele.attachEvent("on"+type,handler);
}else{
ele["on"+type] = handler;
}
},
// 移除事件
removeHandler: function (ele, type, handler) {
if(ele.removeEventListener){
ele.removeEventListener(type,handler,false);
}else if(ele.detachEvent){
ele.detachEvent("on"+type,handler);
}else{
ele["on"+type] = null;
}
},
// 獲取事件對象
getEvent:function (event) {
return event ? event : window.event;
},
// 獲取事件實際目標(biāo)
getTarget:function (event) {
return event.target || event.srcElement;
},
// 阻止默認事件
preventDefault: function (event) {
if(event.preventDefault){
event.preventDefault();
}else{
event.returnValue = false;
}
},
// 阻止事件冒泡
stopPropagation:function (event) {
if(event.stopPropagation){
event.stopPropagation();
}else{
event.cancelBubble = true;
}
},
// 獲取mouseover和mouseout事件觸發(fā)時的相關(guān)元素
getRelatedTarget:function (event) {
if(event.relatedTarget){
return event.relatedTarget;
}else if(event.toElement){
return event.toElement;
}else if(event.fromElement){
return event.fromElement;
}else{
return null;
}
},
// 獲取mousedown和mouseup事件觸發(fā)時的按鍵信息
getButton:function (event) {
if(document.implementation.hasFeature("MouseEvents","2.0")){
return event.button;
}else{
switch (event.button){
case 0:
case 1:
case 3:
case 5:
case 7:
return 0;
case 2:
case 6:
return 2;
case 4:
return 1;
}
}
},
// 獲取mousewheel事件(firefox下為DOMMouseScroll事件)鼠標(biāo)滾輪增量值
getWheelDelta:function (event) {
if(event.wheelDelta){
return event.wheelDelta;
}else {
return -event.detail * 40;
}
},
// 獲取鍵盤事件中按鍵的字符編碼
getCharCode:function (event) {
if(typeof event.charCode === "number"){
return event.charCode;
}else{
return event.keyCode;
}
},
// 獲取剪貼板中的數(shù)據(jù)
getClipboardText:function (event) {
var clip = (event.clipboardData || window.clipboardData);
return clip.getData("text");
},
// 設(shè)置剪貼板中的數(shù)據(jù)
setClipboardText:function (event,value) {
if(event.clipboardData){
return event.clipboardData.setData("text/plain",value);
}else if(window.clipboardData){
return window.clipboardData.setData("text",value);
}
}
};
13.4 事件類型
13.4.1 UI事件
load事件夕玩,當(dāng)頁面完全加載后(包括所有圖像惊豺,JavaScript文件,CSS文件等外部資源)尸昧,就會在window上面觸發(fā)該事件。
圖像上面也可以觸發(fā)load事件烹俗,當(dāng)圖像加載完畢時就會觸發(fā)綁定在img圖像上的load事件萍程,在新建圖像元素時(無論是DOM創(chuàng)建img標(biāo)簽還是創(chuàng)建新的Image對象),只要設(shè)置了src屬性茫负,圖像就會開始下載。為保證能觸發(fā)事件乎赴,要先綁定事件,再為圖像設(shè)置src屬性榕吼。
<script>元素也會觸發(fā)load事件,與圖像不同羹蚣,只有在設(shè)置了<script>元素的src屬性,并且將該元素添加到文檔后顽素,才會開始下載JavaScript文件,所以綁定事件處理程序和設(shè)置src屬性的先后順序沒有需求戈抄。
unload事件离唬,文檔被完全卸載后觸發(fā)划鸽,從一個頁面切換到另一個頁面時,就會觸發(fā)unload事件裸诽。
resize事件,當(dāng)瀏覽器窗口被調(diào)整到一個新的高度或?qū)挾葧r(包括最大化和最小化)丈冬,就會觸發(fā)resize事件。瀏覽器窗口變化的過程中埂蕊,resize事件會被不斷的觸發(fā)。
scroll事件蓄氧,當(dāng)用戶滾動帶滾動條的元素中的內(nèi)容時,在該元素上面觸發(fā)喉童。scroll事件也會在文檔被滾動期間不斷觸發(fā)撇寞。
13.4.2 焦點事件
focus事件,元素獲得焦點時觸發(fā)牌废,不冒泡。
focusin事件鸟缕,與focus等價,但會冒泡恨统。在focus之后觸發(fā)。
blur事件畜埋,元素失去焦點時觸發(fā),不冒泡悠鞍。
focusout事件,與blur等價咖祭,但會冒泡。在blur之后觸發(fā)么翰。
13.4.3 鼠標(biāo)與滾輪事件
click事件,單機鼠標(biāo)左鍵或按下回車時觸發(fā)浩嫌,表示既可以通過鼠標(biāo)也可以通過鍵盤觸發(fā)檐迟。
dblclick事件码耐,雙擊鼠標(biāo)左鍵時觸發(fā)。
mousedown事件骚腥,按下鼠標(biāo)任意按鍵時觸發(fā),不能通過鍵盤觸發(fā)束铭。
mouseup事件,釋放鼠標(biāo)任意按鍵時觸發(fā)契沫,不能通過鍵盤觸發(fā)。
mouseleave事件埠褪,在位于元素上方的鼠標(biāo)光標(biāo)移動到元素范圍之外時觸發(fā)。不冒泡钞速,子元素包含的范圍也是元素的范圍。
mouseenter事件渴语,在鼠標(biāo)光標(biāo)從元素外部首次移動到元素范圍之內(nèi)時觸發(fā)。不冒泡驾凶,子元素包含的范圍也是元素的范圍。
mouseout事件调违,鼠標(biāo)指針從一個元素上方窟哺,移入另一個元素時觸發(fā)且轨,另一個元素可以是這個元素內(nèi)部的子元素。
mouseover事件虚婿,鼠標(biāo)指針位于一個元素外部,然后用戶將其首次移入這個元素邊界之內(nèi)時觸發(fā)然痊。
如果mousedown和mouseup中一個被取消,則不會觸發(fā)click事件剧浸,同樣只有觸發(fā)兩次click事件,才會觸發(fā)dblclick事件辛蚊。
clientX和clientY屬性粤蝎,這兩個屬性保存了鼠標(biāo)事件發(fā)生時初澎,鼠標(biāo)指針在視口中的水平和垂直坐標(biāo)。
pageX和pageY屬性虑凛,這兩個屬性保存了鼠標(biāo)事件發(fā)生時,鼠標(biāo)指針在整個頁面中的水平和垂直坐標(biāo)桑谍。頁面沒有滾動時,與clientX和clientY屬性的值相等锣披。
screenX和screenY屬性贿条,這兩個屬性保存了鼠標(biāo)事件發(fā)生時,鼠標(biāo)指針相對于整個顯示器屏幕的水平和垂直坐標(biāo)整以。
shiftkey、ctrlKey峻仇、altKey、metaKey4個修改鍵屬性為布爾值摄咆,分表表示事件發(fā)生時,Shift吭从、Ctrl、ALT影锈、Meta(Window鍵或Cmd鍵)4個按鍵是否被按下。
mouseover和mouseout事件發(fā)生時鸭廷,DOM為事件對象提供了relatedTarget屬性來表示相關(guān)元素枣抱,mouseover的相關(guān)元素是失去光標(biāo)的那個元素辆床,mouseout的相關(guān)元素是獲得光標(biāo)的元素,其他事件的這個值為null讼载。在IE中,mouseover的相關(guān)元素保存在fromElement屬性中咨堤,mouseout的相關(guān)元素保存在toElement屬性中。
mousedown和mouseup事件發(fā)生時一喘,DOM為事件對象提供了button屬性來表示鼠標(biāo)的按鍵,0表示鼠標(biāo)主按鍵凸克,1表示鼠標(biāo)中鍵(鼠標(biāo)滾輪按鍵)议蟆,2表示鼠標(biāo)次按鍵萎战。
事件對象中還有一個detail屬性,表示在指定位置單擊了多少次蚂维,相繼發(fā)生一次mousedown和一次mouseup算做一次單擊路狮,鼠標(biāo)移動了位置后detail會被重置為0。
滾輪事件mousewheel览祖,當(dāng)用戶通過鼠標(biāo)滾輪與頁面交互時,會觸發(fā)mousewheel事件,事件觸發(fā)時事件對象上有一個wheelDelta屬性又活,向上滾動時苔咪,這個值是120的倍數(shù)柳骄,向下滾動時,這個值是-120的倍數(shù)耐薯。
在Firefox中滾輪事件為DOMMouseScroll,其表示滾輪信息的屬性為detail曲初,向上滾動時,這個值為-3臼婆,向下滾動時,這個值為3颁褂。
觸摸設(shè)備上不支持dblclick事件故响,雙擊瀏覽器窗口會放大畫面颁独,沒有辦法改變其行為。
兩只手指放在屏幕上且頁面隨手指移動時會觸發(fā)mousewheel事件和scroll事件誓酒。
13.4.4 鍵盤與文本事件
keydown事件,按下任意按鍵時觸發(fā)丰捷,按住不放則重復(fù)觸發(fā)。
keypress事件病往,按下任意字符按鍵時觸發(fā),按住不放則重復(fù)觸發(fā)
keyup事件停巷,釋放鍵盤上的按鍵時觸發(fā)耍攘。
textInput事件,在文本插入文本框之前觸發(fā)蕾各。
這4個事件的發(fā)生順序為keydown,keypress式曲,textInput,keyup吝羞,這4個事件也同樣支持修改鍵屬性兰伤。
發(fā)生keydown和keyup事件時敦腔,事件對象keycode中會包含一個鍵碼表示是哪個按鍵,與ASCII碼中的小寫字母或數(shù)字的編碼相同恨溜。與大小寫無關(guān)。唯一不同點為分號糟袁,IE/Safari/Chrome返回186,F(xiàn)irefox/Opera返回59项戴。
keypress事件發(fā)生時,事件對象有一個charCode屬性肯尺,表示所按下按鍵的ASCII編碼沃缘,使用String.fromCharCode()方法可以將其轉(zhuǎn)為實際的字符则吟。
keypress事件和textInput事件的區(qū)別:一是所有可以獲得焦點的元素都會觸發(fā)keypress事件,但只有可編輯區(qū)域會觸發(fā)textInput事件氓仲,二是只有按下能夠?qū)嶋H輸入字符的按鍵才會觸發(fā)textInput事件,但按下影響文本顯示的按鍵也會觸發(fā)keypress事件(例如退格按鍵)敬扛。
13.4.6 變動事件
DOMSubtreeModified事件,當(dāng)DOM結(jié)構(gòu)中發(fā)生任何變化時觸發(fā)啥箭,這個事件在其他任何變動事件觸發(fā)后都會觸發(fā)。
DOMNodeInserted事件急侥,在一個節(jié)點作為子節(jié)點被插入到另一個節(jié)點中時觸發(fā)砌滞。
DOMNodeRemoved事件,在節(jié)點從其父節(jié)點中被移除時觸發(fā)贝润。
DOMNodeInsertedIntoDocument事件,在一個節(jié)點被直接插入文檔打掘,或通過子樹間接插入文檔之后觸發(fā),在DOMNodeInserted之后觸發(fā)尊蚁。
DOMNodeRemoveFromDocument事件唯绍,在一個節(jié)點被直接從文檔中移除枝誊,或通過子樹間接從文檔中移除之后觸發(fā)叶撒,在DOMNodeRemoved之后觸發(fā)。
DOMAttrModified事件耐版,在特性被修改之后觸發(fā)粪牲。
DOMCharacterDataModified事件,在文本節(jié)點的值發(fā)生變化時觸發(fā)腺阳。
在移除節(jié)點時,首先會觸發(fā)DOMNodeRemoved事件亭引,事件目標(biāo)為被刪除的節(jié)點,而事件對象的relatedNode屬性中包含著目標(biāo)父節(jié)點的引用焙蚓,與parentNode相同。被刪除的節(jié)點和其子節(jié)點上购公,會相繼觸發(fā)DOMRemovedFromDocument事件萌京,這個事件不冒泡宏浩。緊隨其后的是DOMSubtreeModified事件,這個事件的事件目標(biāo)是被移除節(jié)點的父節(jié)點比庄。
在插入節(jié)點時较坛,首先會觸發(fā)DOMNodeInserted事件,事件目標(biāo)為被插入的節(jié)點丑勤,而事件對象的relatedNode屬性中包含著目標(biāo)父節(jié)點的引用,緊接著會觸發(fā)DOMNodeInsertedIntoDocument事件吧趣,事件目標(biāo)是被插入的節(jié)點,這個事件不冒泡强挫。最后觸發(fā)DOMSubtreeModified事件,事件目標(biāo)是被插入節(jié)點的父節(jié)點俯渤。
13.4.7 HTML5事件
contextmenu事件,鼠標(biāo)事件的一種八匠,單機鼠標(biāo)右鍵觸發(fā)事件絮爷,可以調(diào)出瀏覽器的上下文菜單梨树,會冒泡,可以使用event.preventDefalut()取消默認的瀏覽器上下文菜單抡四,從而實現(xiàn)自定義菜單的功能。
beforeunload事件指巡,這個事件會在瀏覽器卸載頁面之前觸發(fā),可以通過它來取消卸載并繼續(xù)使用原有頁面藻雪。通過設(shè)置event.returnValue的值(IE鳖谈、Firefox)或?qū)⑿枰@示的信息作為返回值返回(Safari缆娃、Chrome)可以在頁面卸載前為用戶顯示對話框提示用戶是否確認卸載。
DOMContentLoaded事件瑰排,在形成完整的DOM樹之后就會觸發(fā),不用等待圖片之類的外部資源下載椭住。不支持本事件的瀏覽器,可以設(shè)置一個延遲為0的超時調(diào)用:
setTimeout(function () { },0);
超時調(diào)用為0的意思為:在當(dāng)前JavaScript處理完成后立即運行這個函數(shù)。必須將其作為頁面中的第一個超時調(diào)用宅广。
readystatechange事件,提供與文檔或元素的加載狀態(tài)有關(guān)信息跟狱,支持本事件的對象(不是事件對象)都有一個readyState屬性,表示元素的加載狀態(tài)驶臊,可能包含下列5個值:
1.uninitialized:對象存在但未初始化挪挤;
2.loading:對象正在加載數(shù)據(jù)扛门;
3.loaded:對象加載數(shù)據(jù)完成;
4.interactive:可以操作對象了纵寝,但還沒完全加載;
5.complete:對象加載完畢爽茴;
并非所有對象都有全部的5個階段,而且5個階段的順序不一定闹啦,檢測操作時辕坝,需要同時檢測interactive和complete兩個階段。檢測完成時需要同時檢測loaded和complete兩個階段酱畅。并在執(zhí)行一次操作后就將事件處理程序移除琳袄,以防多次執(zhí)行纺酸。
pageshow事件,當(dāng)頁面是通過前進后退等按鈕從內(nèi)存中直接加載餐蔬,會跳過load事件(初次打開頁面時已經(jīng)執(zhí)行過load事件),就會觸發(fā)pageshow事件樊诺,事件目標(biāo)是document,但事件處理程序必須添加到window對象词爬,初次加載時秃嗜,pageshow事件在load事件之后觸發(fā)。事件對象的persisted屬性保存著一個布爾值屬性叽赊,如果頁面被保存在了內(nèi)存當(dāng)中,則為true必搞,否則為false。
pagehide事件顾画,該事件會在瀏覽器卸載頁面時觸發(fā),并且在unload事件之前觸發(fā)研侣,事件目標(biāo)是document,但事件處理程序必須添加到window對象庶诡,事件對象也包含persisted屬性惦银。
當(dāng)?shù)谝淮斡|發(fā)pageshow時(首次加載頁面)扯俱,persisted屬性的值一定是false,而在第一次觸發(fā)pagehide事件時(首次卸載頁面)喇澡,persisted的值會變成true。
hashchange事件晴玖,URL的參數(shù)列表(#號后面的所有字符串)發(fā)生變化時觸發(fā),必須把事件處理程序綁定在window對象上呕屎,事件對象包含oldURL和newURL兩個屬性,分別保存變化前后的完整URL秀睛。最好還是使用location對象來確定當(dāng)前的參數(shù)列表尔当。
13.4.8 設(shè)備事件
orientationchange事件蹂安,在橫屏和豎屏之間切換會觸發(fā)此事件,window.orientation屬性保存狀態(tài)信息田盈,0為豎屏正放,90為主屏按鈕在右橫放缠黍,-90為主屏按鈕在左橫放弄兜。
deviceorientation事件替饿,設(shè)備方向發(fā)生改變時觸發(fā)此事件,觸發(fā)時视卢,事件對象包含著每個軸相對于設(shè)備靜止?fàn)顟B(tài)下發(fā)生的變化信息踱卵。
alpha屬性据过,圍繞Z軸旋轉(zhuǎn)時,Y軸變化的度數(shù)差
beta屬性绳锅,圍繞X軸旋轉(zhuǎn)時,Z軸變化的度數(shù)差
gamma屬性鳞芙,圍繞Y軸旋轉(zhuǎn)時眷柔,Z軸的變化度數(shù)差
devicemotion事件驯嘱,設(shè)備發(fā)生移動的時候觸發(fā),事件對象包含下列屬性:
acceleration屬性喳坠,一個包含x,y,z屬性的對象,在不考慮重力的情況下在每個方向上的加速度壕鹉。
accelerationIncludingGravity屬性,一個包含x,y,z屬性的對象御板,在考慮重力的情況下在每個方向上的加速度锥忿。
interval屬性怠肋,以毫秒表示的時間值。
rotationRate屬性笙各,包含alpha,beta杈抢,gamma三個方向?qū)傩缘膶ο?/p>
13.4.9 觸摸與手勢事件
touchstart事件,手指觸摸屏幕時觸發(fā)仑性,即使已經(jīng)有一個手指放在屏幕上也會觸發(fā)。
touchmove事件,當(dāng)手指在屏幕上滑動時連續(xù)觸發(fā)歼捐,事件發(fā)生時,調(diào)用preventDefault()可以阻止?jié)L動豹储。
touchend事件,當(dāng)手指從屏幕上移開時觸發(fā)剥扣。
每個觸摸事件的事件對象都包含了鼠標(biāo)事件中的常見屬性,觸摸事件對象還包含下列3個用于跟蹤觸摸的屬性:
touches屬性钠怯,表示當(dāng)前跟蹤的觸摸操作的Touch對象的數(shù)組佳魔。
targetTouches屬性呻疹,特定于事件目標(biāo)的Touch對象的數(shù)組。
changeTouches屬性刽锤,表示自上次觸摸以來發(fā)生了什么改變的Touch對象的數(shù)組。
在touchend事件發(fā)生時并思,touches集合中就沒有任何Touch對象了,因為不存在活動的觸摸操作宋彼,此時必須轉(zhuǎn)而使用changeTouches集合弄砍。
觸摸屏幕上的元素時输涕,事件觸發(fā)順序如下:touchstart,mouseover莱坎,mousemove,mousedown檐什,mouseup碴卧,click乃正,touchend。
手勢事件瓮具,當(dāng)兩個手指觸摸屏幕時就會產(chǎn)生手勢凡人,觸發(fā)手勢事件。有3個手勢事件:
gesturestart事件划栓,當(dāng)一個手指已經(jīng)按在屏幕上,另一個手指又觸摸屏幕時觸發(fā)条获。
gesturechange事件,當(dāng)觸摸屏幕的任何一個手指的位置發(fā)生變化時觸發(fā)帅掘。
gestureend事件,當(dāng)任何一個手指從屏幕上面移開時觸發(fā)修档。
只有當(dāng)兩只手指都觸摸到事件的接收容器上時才會觸發(fā)手勢事件碧绞,放上第一只手指時吱窝,會觸發(fā)touchstart事件,放上第二只手指時院峡,會先觸發(fā)gesturestart事件,再觸發(fā)第二只手指的touchstart事件照激,有一個或兩個手指在屏幕上滑動時,將會觸發(fā)gesturechange事件俩垃,只要有一個手指移開励幼,就會觸發(fā)gestureend事件口柳,緊接著又會觸發(fā)該手指的touchend事件。
與觸摸事件一樣跃闹,手勢事件的事件對象也包含所有常見的屬性,還包含額外的兩個屬性rotation和scale屬性辣卒。
rotation屬性表示手指變化引起的旋轉(zhuǎn)角度掷贾,負值表示逆時針旋轉(zhuǎn)荣茫,正值表示順時針旋轉(zhuǎn)(從0開始),scale屬性表示兩個手指間距離的變化情況啡莉,距離拉大增長港准,距離縮短減羞中馈(從1開始)。