1.事件流
1.1事件冒泡
IE的事件流叫做事件冒泡,事件開始時由最具體的元素節(jié)點接收,逐步向上傳播。
<!DOCTYPE html>
<html>
<head>
<title>Event Bubbling Example</title>
</head>
<body>
<div id="myDiv">Click Me</div>
</body>
</html>
如果你在div設(shè)置了一個點擊事件,則傳播順序:1.div 2.body 3.html 4.document
1.2 事件捕獲
不太具體的節(jié)點應(yīng)該更早的接收事件。在事件達(dá)到預(yù)期目標(biāo)之前捕獲它。
仍然是上面的例子,事件捕獲順序:1.document 2.html 3.body 4.div
1.3 DOM事件流
DOM事件流分為三個階段:事件捕獲、目標(biāo)階段、事件冒泡。
2.事件處理程序
事件是用戶或者瀏覽器自身執(zhí)行的動作。響應(yīng)某個事件的函數(shù)叫做事件處理程序。
2.1 HTML事件處理程序
通過html的方式實現(xiàn)一個onclick事件
<input type = "button" onclick = "alert("hellp")">
2.2 DOM0級事件處理程序
這也是現(xiàn)在最常用的一種方法。為啥常用?原因一是簡單,原因二具有跨瀏覽器優(yōu)勢。
var btn = document.getElementById("myBtn");
btn.onclick = function () {
alert("hello");
};
2.3 DOM2級事件處理程序
“DOM2級事件”定義了兩個方法,用于處理指定和刪除事件處理程序的操作:addEventListener()和removeEventListener()。
所有的DOM節(jié)點都包含這兩個方法。接收三個參數(shù):要處理的時間名、作為事件處理程序的函數(shù)和布爾值。最后這個布爾值是true,表示在捕獲節(jié)點調(diào)用時間處理程序;如果是false,表示在冒泡階段調(diào)用時間處理程序。
var btn = document.getElementById("myBtn");
btn.addEventListener("click", function(){
alert(this.id);
}, false);
btn.addEventListener("click", function(){
alert("Hello world!");
}, false);
2.4 IE事件處理程序
IE實現(xiàn)了DOM中類似的兩個方法:attachEvent()和detachEvent()。這兩個方法接收相同的兩個參數(shù):事件處理程序名稱與時間處理程序函數(shù)。IE8及更早的版本只支持事件冒泡,所以通過attachEvent()添加的時間處理程序都會被添加到冒泡階段。
var btn = document.getElementById("myBtn");
btn.attachEvent("onclick", function(){
alert("Clicked");
});
btn.attachEvent("onclick", function(){
alert("Hello world!");
});
2.5 跨瀏覽器的事件處理程序
要保證處理事件的帶啊能在大多數(shù)瀏覽器下一致的執(zhí)行,只需要關(guān)注冒泡階段。
第一個要創(chuàng)建的放大是addHandler(),它的作用是視情況而定分別使用DOM0級方法、DOM2級方法或IE方法來添加事件。addHandle()接受三個參數(shù):要操作的元素、事件名稱和事件處理程序函數(shù)。
var EventUtil = {
addHandler: function(element, type, handler){
if (element.addEventListener){
element.addEventListener(type, handler, false);
} else if (element.attachEvent){
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;
} }
};
3.事件對象
在觸發(fā)DOM上的某個事件時,會產(chǎn)生一個event對象,這個對象中包含素有時間有關(guān)的信息。事件的元素、事件的類型及其他相關(guān)信息。例如,鼠標(biāo)點擊導(dǎo)致的事件,可以獲取到鼠標(biāo)點擊的位置;鍵盤操作導(dǎo)致的事件,會包含與按下的鍵有關(guān)的信息。
3.1 DOM中的時間對象
兼容DOM的瀏覽器會將一個event對象傳入到時間處理程序中。無論指定時間處理程序時使用什么方法,都會傳入event對象。
var btn = document.getElementById("myBtn");
btn.onclick = function(event){
alert(event.type); //"click"
};
btn.addEventListener("click", function(event){
alert(event.type); //"click"
}, false);
關(guān)于Event對象包含的屬性與方法
| 屬性/方法 | 類型 | 讀/寫 | 說明 |
|---|---|---|---|
| bubbles | boolean | 只讀 | 表明時間是否冒泡 |
| cancelable | boolean | 只讀 | 表名是否可以取消事件默認(rèn)行為 |
| currentTarget | Element | 只讀 | 其事件處理程序當(dāng)前正在處理事件的那個元素 |
| defaultPrevented | boolean | 只讀 | 為true表示已經(jīng)調(diào)用了preventDefault() |
| detail | Integer | 只讀 | 與事件相關(guān)的細(xì)節(jié)信息 |
| eventPhase | Integer | 只讀 | 調(diào)用時間處理程序的階段,1表示捕獲階段,2表示處于目標(biāo),3表示冒泡階段 |
| preventDefault() | Function | 只讀 | 取消事件默認(rèn)行為 |
| stopImmediatePropagation() | Function | 只讀 | 取消事件的進(jìn)一步捕獲或冒泡,同時阻止任何事件處理程序被調(diào)用 |
| stopPropagation() | Function | 只讀 | 取消事件的進(jìn)一步捕獲或冒泡,如果bubbles為true,則可以使用這個方法 |
| target | Element | 只讀 | 事件的目標(biāo) |
| trusted | boolean | 只讀 | 為true表示事件是瀏覽器生成。false表示事件使用開發(fā)人員通過JS創(chuàng)建 |
| type | String | 只讀 | 被觸發(fā)事件的類型 |
| view | AbstractView | 只讀 | 與事件關(guān)聯(lián)的抽象視圖。等同于發(fā)生事件的window對象 |
在對象處理程序內(nèi)部,對象this扥估currentTarget的值。
var btn = document.getElementById("myBtn");
btn.onclick = function(event) {
alert(event.currentTarget === this); //true
alert(event.target === this); //true
};
4.事件類型
事件類型分類:UI事件、焦點事件、鼠標(biāo)事件、滾輪事件、文本事件、鍵盤事件、合成事件、變動事件。
4.1 UI事件
1.load事件:JS中最常用的就是load事件。當(dāng)頁面加載后就會觸發(fā)window上的load事件。如何定義onload事件呢?可以看下demo
第一種,JS聲明
EventUtil.addHandler(window, "load", function(event){
alert("Loaded");
});
第二種,標(biāo)簽屬性
<body onload="alert('Loaded!')">
2.unload事件:文檔被完全卸載后觸發(fā)。只要用戶從一個頁面切換到另一個頁面就會觸發(fā)unload。利用這個事件最多的情況是清除引用,避免內(nèi)存泄露。
第一種,JS聲明
EventUtil.addHandler(window, "unload", function(event){
alert("Unloaded");
});
第二種,標(biāo)簽屬性
<body onunload="alert('Loaded!')">
3.resize事件:當(dāng)瀏覽器窗口被調(diào)整到一個新的高度或?qū)挾葧r,就會觸發(fā)resize事件。注意resize事件會頻繁被觸發(fā),所以在盡量不要書寫大量運算邏輯,會導(dǎo)致瀏覽器變慢。
第一種,JS聲明
EventUtil.addHandler(window, "resize", function(event){
alert("Resized");
});
第二種,標(biāo)簽屬性
<body onresize="alert('Loaded!')">
4.scroll事件:當(dāng)用戶滾動帶滾動條的元素內(nèi)容時觸發(fā)。在window對象上發(fā)生的,表示頁面中響應(yīng)元素的變化。跟resize事件類似,scroll會頻發(fā)觸發(fā)。所以在盡量不要書寫大量運算邏輯,會導(dǎo)致瀏覽器變慢
EventUtil.addHandler(window, "scroll", function(event){
if (document.compatMode == "CSS1Compat"){
alert(document.documentElement.scrollTop);
} else {
alert(document.body.scrollTop);
}
});
4.2 焦點事件(這里就不寫demo了,會對事件做一個詳細(xì)的分析)
- blur:在元素市區(qū)焦點時觸發(fā)。這個事件不會冒泡(但是可以捕獲階段監(jiān)聽到)
- focus:在元素獲得焦點時觸發(fā)。這個事件不會冒泡(但是可以捕獲階段監(jiān)聽到)
- focusion:在元素獲得焦點時觸發(fā)。這個事件會冒泡
- focusout:在元素失去焦點時觸發(fā)。這個事件會冒泡
4.3 滾動與滾輪事件
- click:在用戶單擊主鼠標(biāo)按鈕或者回車鍵觸發(fā)
- dblclick:在用戶雙擊主鼠標(biāo)按鈕時觸發(fā)
- mousedown:在用戶按下任意鼠標(biāo)按鈕時觸發(fā)。
- mouseenter:鼠標(biāo)光標(biāo)從元素外部首次移動到元素范圍內(nèi)觸發(fā)。(IE、Firefox 9+和Opera支持)
- mouseleave:在位于元素上方的鼠標(biāo)光標(biāo)移動到元素范圍之外時候觸發(fā)。(IE、Firefox 9+和Opera支持)
- mousemove:當(dāng)鼠標(biāo)指針在元素內(nèi)部移動時重復(fù)觸發(fā)。
- mouseout:在鼠標(biāo)指針位于一個元素上方,然后用戶將其移入另一個元素時觸發(fā)。
- mouseover:在鼠標(biāo)指針位于一個元素外部,然后用戶將其移入另一個元素邊界之內(nèi)時觸發(fā)。
- mouseup:在用戶釋放鼠標(biāo)按鈕時觸發(fā)。
1.客戶區(qū)坐標(biāo)位置(整個瀏覽器去掉工具欄等其他輔助工具的位置)
var div = document.getElementById("MyDiv");
EventUtil.addHandler(div, "click", function(event){
event = EventUtil.getEvent(event);
alert("Client coordinates: " + event.clientX + "," + event.clientY);
});
2.頁面坐標(biāo)位置
var div = document.getElementById("MyDiv");
EventUtil.addHandler(div, "click", function(event){
event = EventUtil.getEvent(event);
alert("Page coordinates: " + event.pageX + "," + event.pageY);
});
3.屏幕坐標(biāo)位置(獲取的是整個用戶操作系統(tǒng)界面的坐標(biāo))
var div = document.getElementById("myDiv");
EventUtil.addHandler(div, "click", function(event){
event = EventUtil.getEvent(event);
alert("Screen coordinates: " + event.screenX + "," + event.screenY);
});
4.修改鍵
修改鍵就是Shift、Ctrl、Alt,這些經(jīng)常被用來修改鼠標(biāo)性情。因此DOM規(guī)定了四個屬性,來修改這些按鍵的狀態(tài):shiftKey、ctrlKey、altKey和metaKey。這些屬性都是布爾值,如果這些按鍵按下了則為true,否則為false。
var div = document.getElementById("myDiv");
EventUtil.addHandler(div, "click", function(event){
event = EventUtil.getEvent(event);
var keys = new Array();
if (event.shiftKey){
keys.push("shift");
}
if (event.ctrlKey){
keys.push("ctrl");
}
if (event.altKey){
keys.push("alt");
}
if (event.metaKey){
keys.push("meta");
}
alert("Keys: " + keys.join(","));
});
4.4 鍵盤與文本事件
- keydown:當(dāng)用戶按下鍵盤上任意鍵時觸發(fā)。按住不放,重復(fù)執(zhí)行此事件
- keypress:當(dāng)用戶按下鍵盤上的字符鍵時觸發(fā)。按住不放,重復(fù)執(zhí)行此事件
- keyup:當(dāng)用戶釋放按鍵時觸發(fā)
1.鍵碼
鍵盤上每個按鍵都有一個keyCode屬性用于標(biāo)識按鍵的。
var textbox = document.getElementById("myText");
EventUtil.addHandler(textbox, "keyup", function(event){
event = EventUtil.getEvent(event);
alert(event.keyCode);
});
2.字符編碼
瀏覽器event對象都支持一個charCode屬性,這個屬性只有在發(fā)生keypress事件才有值,而且這個值是安縣哪個鍵鎖代表的字符的ASCII編碼。通常用來檢驗瀏覽器字符集。
3.textInput事件
用戶在可編輯區(qū)域中輸入字符時,就會觸發(fā)這個事件。
var textbox = document.getElementById("myText");
EventUtil.addHandler(textbox, "textInput", function(event){ event = EventUtil.getEvent(event);
alert(event.data);
});
5.內(nèi)存與性能
5.1 事件委托
對事件處理程序過多的時候,就可以通過委托的方式去解決。事件委托利用了事件冒泡。指定一個事件處理程序,就可以管理一類型所有的事件。
<ul id="myLinks">
<li id="goSomewhere">Go somewhere</li>
<li id="doSomething">Do something</li>
<li id="sayHi">Say hi</li>
</ul>
function getEvent(){
var list = document.getElementById("myLinks");
EventUtil.addHandler(list, "click", function(event){
event = EventUtil.getEvent(event);
var target = EventUtil.getTarget(event);
}
}
5.2 移除事件處理程序
每當(dāng)事件處理程序指定元素時,運行中的瀏覽器代碼與支持頁面交互的JS代碼會建立一個鏈接。這種鏈接越多,頁面執(zhí)行越慢??梢詢煞N方式規(guī)避這個問題,可以采用事件委托技術(shù)限制建立連接數(shù)。另外,在不需要的時候移除事件處理程序。
btn.onclick = funciotn(){
//執(zhí)行某些操作
btn.onclick = null; //移除事件處理程序
document.getElementById("myDiv").innerHTML = "Processing...";
};