JavaScript 與 HTML 之間的交互是通過事件實現(xiàn)的趣斤。事件土至,就是文檔或瀏覽器窗口中發(fā)生的一些特定的交互瞬間》成可以使用偵聽器(或處理程序)來預(yù)訂事件臂港,以便事件發(fā)生時執(zhí)行相應(yīng)的代碼森枪。
一、事件流
事件流描述的是從頁面中接收事件的順序审孽。
1县袱、事件冒泡
IE 的事件流叫做事件冒泡(event bubbling),即事件開始時由最具體的元素(文檔中嵌套層次最深的那個節(jié)點)接收佑力,然后逐級向上傳播到較為不具體的節(jié)點(文檔)式散。
<!DOCTYPE html>
<html>
<head>
<title>Event Bubbling Example</title>
</head>
<body>
<div id="myDiv">Click Me</div>
</body>
</html>
//如果你單擊了頁面中的 <div> 元素,那么這個 click 事件會按照如下順序傳播:
(1) <div>
(2) <body>
(3) <html>
(4) document
所有現(xiàn)代瀏覽器都支持事件冒泡搓萧,但在具體實現(xiàn)上存在一些差別杂数。
2、事件捕獲
事件捕獲的思想是不太具體的節(jié)點應(yīng)該更早接收到事件瘸洛,而最具體的節(jié)點應(yīng)該最后接收到事件揍移。事件捕獲的用意在于在事件到達預(yù)定目標之前捕獲它。
事件捕獲觸發(fā)的 click 事件:
(1) document
(2) <html>
(3) <body>
(4) <div>
由于老版本的瀏覽器不支持反肋,因此很少有人使用事件捕獲那伐。
3、DOM事件流
“DOM2級事件”規(guī)定的事件流包括三個階段:事件捕獲階段石蔗、處于目標階段和事件冒泡階段罕邀。首先發(fā)生的是事件捕獲,為截獲事件提供了機會养距。然后是實際的目標接收到事件诉探。最后一個階段是冒泡階段,可以在這個階段對事件做出響應(yīng)棍厌。
二肾胯、事件處理程序
響應(yīng)某個事件的函數(shù)就叫做事件處理程序(或事件偵聽器)。事件處理程序的名字以 "on" 開頭耘纱,因此click 事件的事件處理程序就是 onclick 敬肚, load 事件的事件處理程序就是 onload 。
1束析、HTML事件處理程序
某個元素支持的每種事件艳馒,都可以使用一個與相應(yīng)事件處理程序同名的 HTML 特性來指定。這個特性的值應(yīng)該是能夠執(zhí)行的 JavaScript 代碼员寇。
// HTML 中定義的事件
<input type="button" value="Click Me" onclick="alert('Clicked')" />
//調(diào)用腳本形式
<input type="button" value="Click Me" onclick="showMessage()" />
<script type="text/javascript">
function showMessage(){
alert("Hello world!");
}
</script>
2弄慰、DOM0級事件處理程序
通過 JavaScript 指定事件處理程序的傳統(tǒng)方式第美,就是將一個函數(shù)賦值給一個事件處理程序?qū)傩浴_@種為事件處理程序賦值的方法是在第四代 Web 瀏覽器中出現(xiàn)的曹动,而且至今仍然為所有現(xiàn)代瀏覽器所支持斋日。原因一是簡單牲览,二是具有跨瀏覽器的優(yōu)勢墓陈。要使用 JavaScript 指定事件處理程序,首先必須取得一個要操作的對象的引用第献。
每個元素(包括 window 和 document )都有自己的事件處理程序?qū)傩怨北兀@些屬性通常全部小寫,例如 onclick 庸毫。將這種屬性的值設(shè)置為一個函數(shù)仔拟,就可以指定事件處理程序。
var btn = document.getElementById("myBtn");
btn.onclick = function(){
alert("Clicked");
};
通過文檔對象取得了一個按鈕的引用飒赃,然后為它指定了 onclick 事件處理程序利花。
使用 DOM0 級方法指定的事件處理程序被認為是元素的方法。因此载佳,這時候的事件處理程序是在元素的作用域中運行炒事;換句話說,程序中的 this 引用當(dāng)前元素蔫慧。
var btn = document.getElementById("myBtn");
btn.onclick = function(){
alert(this.id); //"myBtn"
};
不僅僅是 ID挠乳,實際上可以在事件處理程序中通過 this 訪問元素的任何屬性和方法。以這種方式添加的事件處理程序會在事件流的冒泡階段被處理姑躲。
也可以刪除通過 DOM0 級方法指定的事件處理程序睡扬。
btn.onclick = null; //刪除事件處理程序
將事件處理程序設(shè)置為 null 之后,再單擊按鈕將不會有任何動作發(fā)生黍析。
3卖怜、DOM2級事件處理程序
“DOM2級事件”定義了兩個方法,用于處理指定和刪除事件處理程序的操作: addEventListener()和 removeEventListener() 阐枣。所有 DOM 節(jié)點中都包含這兩個方法马靠,并且它們都接受 3 個參數(shù):要處理的事件名、作為事件處理程序的函數(shù)和一個布爾值侮繁。最后這個布爾值參數(shù)如果是 true 虑粥,表示在捕獲階段調(diào)用事件處理程序;如果是 false 宪哩,表示在冒泡階段調(diào)用事件處理程序娩贷。
var btn = document.getElementById("myBtn");
btn.addEventListener("click", function(){
alert(this.id);
}, false);
通過 addEventListener() 添加的事件處理程序只能使用 removeEventListener() 來移除;移除時傳入的參數(shù)與添加處理程序時使用的參數(shù)相同锁孟。這也意味著通過 addEventListener() 添加的匿名函數(shù)將無法移除彬祖。
var btn = document.getElementById("myBtn");
btn.addEventListener("click", function(){
alert(this.id);
}, false);
// 匿名函數(shù)
btn.removeEventListener("click", function(){ // 沒有用茁瘦!
alert(this.id);
}, false);
var handler = function(){
alert(this.id);
};
btn.addEventListener("click", handler, false);
// 傳入函數(shù)名
btn.removeEventListener("click", handler, false); // 有效!
傳入 removeEventListener() 中的事件處理程序函數(shù)必須與傳入addEventListener() 中的相同储笑。
4甜熔、IE事件處理程序
IE 實現(xiàn)了與 DOM 中類似的兩個方法: attachEvent() 和 detachEvent() 。這兩個方法接受相同的兩個參數(shù):事件處理程序名稱與事件處理程序函數(shù)突倍。
var btn = document.getElementById("myBtn");
btn.attachEvent("onclick", function(){
alert("Clicked");
});
注意腔稀, attachEvent() 的第一個參數(shù)是 "onclick" ,而非 DOM 的 addEventListener() 方法中的 "click" 羽历。
在 IE 中使用 attachEvent() 與使用 DOM0 級方法的主要區(qū)別在于事件處理程序的作用域焊虏。在使用 DOM0 級方法的情況下,事件處理程序會在其所屬元素的作用域內(nèi)運行秕磷;在使用 attachEvent() 方法的情況下诵闭,事件處理程序會在全局作用域中運行,因此 this 等于 window 澎嚣。
var btn = document.getElementById("myBtn");
btn.attachEvent("onclick", function(){
alert(this === window); //true
});
使用 attachEvent() 添加的事件可以通過 detachEvent() 來移除疏尿,條件是必須提供相同的參數(shù)。與 DOM 方法一樣易桃,這也意味著添加的匿名函數(shù)將不能被移除褥琐。不過,只要能夠?qū)ο嗤瘮?shù)的引用傳給 detachEvent() 颈抚,就可以移除相應(yīng)的事件處理程序踩衩。
var btn = document.getElementById("myBtn");
var handler = function(){
alert("Clicked");
};
btn.attachEvent("onclick", handler);
// 移除相應(yīng)事件
btn.detachEvent("onclick", handler);
5、跨瀏覽器的事件處理程序
addHandler() 方法接受 3 個參數(shù):要操作的元素贩汉、事件名稱和事件處理程序函數(shù)驱富。它的職責(zé)是視情況分別使用 DOM0 級方法、DOM2 級方法或 IE 方法來添加事件匹舞。這個方法屬于一個名叫 EventUtil 的對象褐鸥。
與 addHandler() 對應(yīng)的方法是 removeHandler() ,它也接受相同的參數(shù)赐稽。這個方法的職責(zé)是移除之前添加的事件處理程序叫榕。
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;
}
}
};
使用 EventUtil 對象:
var btn = document.getElementById("myBtn");
var handler = function(){
alert("Clicked");
};
EventUtil.addHandler(btn, "click", handler);
// 這里省略了其他代碼
EventUtil.removeHandler(btn, "click", handler);
三、事件對象
在觸發(fā) DOM 上的某個事件時姊舵,會產(chǎn)生一個事件對象 event 晰绎,這個對象中包含著所有與事件有關(guān)的信息。包括導(dǎo)致事件的元素括丁、事件的類型以及其他與特定事件相關(guān)的信息荞下。
1、DOM中的事件對象
兼容 DOM 的瀏覽器會將一個 event 對象傳入到事件處理程序中。
var btn = document.getElementById("myBtn");
btn.onclick = function(event){
alert(event.type); //"click"
};
btn.addEventListener("click", function(event){
alert(event.type); //"click"
}, false);
//通過 HTML 特性指定事件處理程序時尖昏,變量 event 中保存著 event 對象
<input type="button" value="Click Me" onclick="alert(event.type)"/>
event 對象包含與創(chuàng)建它的特定事件有關(guān)的屬性和方法仰税。觸發(fā)的事件類型不一樣,可用的屬性和方法也不一樣抽诉。
在事件處理程序內(nèi)部陨簇,對象 this 始終等于 currentTarget 的值,而 target 則只包含事件的實際目標迹淌。如果直接將事件處理程序指定給了目標元素河绽,則 this 、 currentTarget 和 target 包含相同的值巍沙。
var btn = document.getElementById("myBtn");
btn.onclick = function(event){
alert(event.currentTarget === this); //true
alert(event.target === this); //true
};
//事件處理程序存在于按鈕的父節(jié)點中
document.body.onclick = function(event){
alert(event.currentTarget === document.body); //true
alert(this === document.body); //true
alert(event.target === document.getElementById("myBtn")); //true
};
在需要通過一個函數(shù)處理多個事件時葵姥,可以使用 type 屬性荷鼠。
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;
要阻止特定事件的默認行為句携,可以使用 preventDefault() 方法。例如允乐,阻止鏈接的默認行為:
var link = document.getElementById("myLink");
link.onclick = function(event){
event.preventDefault();
};
只有 cancelable 屬性設(shè)置為 true 的事件矮嫉,才可以使用 preventDefault() 來取消其默認行為。
stopPropagation() 方法用于立即停止事件在 DOM 層次中的傳播牍疏,即取消進一步的事件捕獲或冒泡蠢笋。
var btn = document.getElementById("myBtn");
btn.onclick = function(event){
alert("Clicked");
event.stopPropagation();
};
document.body.onclick = function(event){
alert("Body clicked");
};
如果不調(diào)用 stopPropagation() ,就會在單擊按鈕時出現(xiàn)兩個警告框鳞陨。
事件對象的 eventPhase 屬性昨寞,可以用來確定事件當(dāng)前正位于事件流的哪個階段。
var btn = document.getElementById("myBtn");
btn.onclick = function(event){
alert(event.eventPhase); //2
};
document.body.addEventListener("click", function(event){
alert(event.eventPhase); //1
}, true);
document.body.onclick = function(event){
alert(event.eventPhase); //3
};
提示:只有在事件處理程序執(zhí)行期間厦滤, event 對象才會存在援岩;一旦事件處理程序執(zhí)行完成, event 對象就會被銷毀掏导。
2享怀、IE中的事件對象
與訪問 DOM 中的 event 對象不同,要訪問 IE 中的 event 對象有幾種不同的方式趟咆,取決于指定事件處理程序的方法添瓷。
在使用 DOM0 級方法添加事件處理程序時, event 對象作為 window 對象的一個屬性存在值纱。
var btn = document.getElementById("myBtn");
btn.onclick = function(){
var event = window.event;
alert(event.type); //"click"
};
如果事件處理程序是使用 attachEvent() 添加的鳞贷,那么就會有一個 event 對象作為參數(shù)被傳入事件處理程序函數(shù)中。
var btn = document.getElementById("myBtn");
btn.attachEvent("onclick", function(event){
alert(event.type); //"click"
});
如果是通過HTML特性指定的事件處理程序虐唠,那么還可以通過一個名叫 event 的變量來訪問 event對象(與 DOM中的事件模型相同)搀愧。
<input type="button" value="Click Me" onclick="alert(event.type)">
IE 的 event 對象同樣也包含與創(chuàng)建它的事件相關(guān)的屬性和方法。
因為事件處理程序的作用域是根據(jù)指定它的方式來確定的,所以不能認為 this 會始終等于事件目標妈橄。故而庶近,最好還是使用 event.srcElement 比較保險。
var btn = document.getElementById("myBtn");
btn.onclick = function(){
alert(window.event.srcElement === this); //true
};
btn.attachEvent("onclick", function(event){
alert(event.srcElement === this); //false
});
returnValue 屬性相當(dāng)于 DOM中的 preventDefault() 方法眷蚓,作用都是取消
給定事件的默認行為鼻种。只要將 returnValue 設(shè)置為 false ,就可以阻止默認行為沙热。
var link = document.getElementById("myLink");
link.onclick = function(){
window.event.returnValue = false;
};
cancelBubble 屬性與 DOM 中的 stopPropagation() 方法作用相同叉钥,都是用來停止事件冒泡的。但 stopPropagatioin() 可以同時取消事件捕獲和冒泡篙贸。
var btn = document.getElementById("myBtn");
btn.onclick = function(){
alert("Clicked");
window.event.cancelBubble = true;
};
document.body.onclick = function(){
alert("Body clicked");
};
3投队、跨瀏覽器的事件對象
雖然 DOM 和 IE 中的 event 對象不同,但基于它們之間的相似性依舊可以拿出跨瀏覽器的方案來爵川。
var EventUtil = {
addHandler: function(element, type, handler) {
//省略的代碼
},
//返回對 event對象的引用敷鸦。
getEvent: function(event) {
return event ? event : window.event;
},
//返回事件的目標
getTarget: function(event) {
return event.target || event.srcElement;
},
//取消事件的默認行為
preventDefault: function(event) {
if (event.preventDefault) {
event.preventDefault();
} else {
event.returnValue = false;
}
},
removeHandler: function(element, type, handler) {
//省略的代碼
},
//取消事件捕獲和冒泡
stopPropagation: function(event) {
if (event.stopPropagation) {
event.stopPropagation();
} else {
event.cancelBubble = true;
}
}
};
var btn = document.getElementById("myBtn");
// getEvent()的使用方法
btn.onclick = function(event) {
event = EventUtil.getEvent(event);
};
// getTarget()的使用方法
btn.onclick = function(event) {
event = EventUtil.getEvent(event);
var target = EventUtil.getTarget(event);
};
//取消事件的默認行為
var link = document.getElementById("myLink");
link.onclick = function(event) {
event = EventUtil.getEvent(event);
EventUtil.preventDefault(event);
};
//
btn.onclick = function(event) {
alert("Clicked");
event = EventUtil.getEvent(event);
EventUtil.stopPropagation(event);
};
document.body.onclick = function(event) {
alert("Body clicked");
};
stopPropagation()方法由于 IE 不支持事件捕獲,因此這個方法在跨瀏覽器的情況下寝贡,只能用來阻止事件冒泡扒披。
四、事件類型
“DOM3級事件”規(guī)定了以下幾類事件:
- UI(User Interface圃泡,用戶界面)事件碟案,當(dāng)用戶與頁面上的元素交互時觸發(fā);
- 焦點事件颇蜡,當(dāng)元素獲得或失去焦點時觸發(fā)价说;
- 鼠標事件,當(dāng)用戶通過鼠標在頁面上執(zhí)行操作時觸發(fā)风秤;
- 滾輪事件鳖目,當(dāng)使用鼠標滾輪(或類似設(shè)備)時觸發(fā);
- 文本事件唁情,當(dāng)在文檔中輸入文本時觸發(fā)疑苔;
- 鍵盤事件,當(dāng)用戶通過鍵盤在頁面上執(zhí)行操作時觸發(fā)甸鸟;
- 合成事件惦费,當(dāng)為 IME(Input Method Editor,輸入法編輯器)輸入字符時觸發(fā)抢韭;
- 變動(mutation)事件薪贫,當(dāng)?shù)讓?DOM 結(jié)構(gòu)發(fā)生變化時觸發(fā)。
- 變動名稱事件刻恭,當(dāng)元素或?qū)傩悦儎訒r觸發(fā)瞧省。此類事件已經(jīng)被廢棄
1扯夭、UI事件
UI 事件指的是那些不一定與用戶操作有關(guān)的事件。
- load :當(dāng)頁面完全加載后在 window 上面觸發(fā)鞍匾,當(dāng)所有框架都加載完畢時在框架集上面觸發(fā)交洗,當(dāng)圖像加載完畢時在 <img> 元素上面觸發(fā),或者當(dāng)嵌入的內(nèi)容加載完畢時在 <object> 元素上面觸發(fā)橡淑。
- unload :當(dāng)頁面完全卸載后在 window 上面觸發(fā)构拳,當(dāng)所有框架都卸載后在框架集上面觸發(fā),或者當(dāng)嵌入的內(nèi)容卸載完畢后在 <object> 元素上面觸發(fā)梁棠。
- abort :在用戶停止下載過程時置森,如果嵌入的內(nèi)容沒有加載完,則在 <object> 元素上面觸發(fā)符糊。
- error :當(dāng)發(fā)生 JavaScript 錯誤時在 window 上面觸發(fā)凫海,當(dāng)無法加載圖像時在 <img> 元素上面觸發(fā),當(dāng)無法加載嵌入內(nèi)容時在 <object> 元素上面觸發(fā)男娄,或者當(dāng)有一或多個框架無法加載時在框架集上面觸發(fā)行贪。
- select :當(dāng)用戶選擇文本框( <input> 或 <texterea> )中的一或多個字符時觸發(fā)
- resize :當(dāng)窗口或框架的大小變化時在 window 或框架上面觸發(fā)。
- scroll :當(dāng)用戶滾動帶滾動條的元素中的內(nèi)容時沪伙,在該元素上面觸發(fā)瓮顽。 <body> 元素中包含所加載頁面的滾動條。
要確定瀏覽器是否支持 DOM2 級事件規(guī)定的 HTML 事件:
var isSupported = document.implementation.hasFeature("HTMLEvents", "2.0");
注意围橡,只有根據(jù)“DOM2 級事件”實現(xiàn)這些事件的瀏覽器才會返回 true 。而以非標準方式支持這些事件的瀏覽器則會返回 false 缕贡。
要確定瀏覽器是否支持“DOM3 級事件”定義的事件:
var isSupported = document.implementation.hasFeature("UIEvent", "3.0");
(1) load 事件
load 事件JavaScript 中最常用的一個事件就是 load 翁授。當(dāng)頁面完全加載后(包括所有圖像、JavaScript 文件晾咪、CSS 文件等外部資源)收擦,就會觸發(fā) window 上面的 load 事件。
有兩種定義 onload 事件處理程序的方式谍倦。
第一種:通過 JavaScript 來指定事件處理程序的方式塞赂,使用了跨瀏覽器的 EventUtil對象。
EventUtil.addHandler(window, "load", function(event){
alert("Loaded!");
});
第二種:指定 onload 事件處理程序的方式是為 <body> 元素添加一個 onload 特性昼蛀。
<!DOCTYPE html>
<html>
<head>
<title>Load Event Example</title>
</head>
<body onload="alert('Loaded!')">
</body>
</html>
建議盡可能使用 JavaScript 方式宴猾。
(2)unload事件
與 load 事件對應(yīng)的是 unload 事件,這個事件在文檔被完全卸載后觸發(fā)叼旋。只要用戶從一個頁面切換到另一個頁面仇哆,就會發(fā)生 unload 事件。而利用這個事件最多的情況是清除引用夫植,以避免內(nèi)存泄漏讹剔。
有兩種指定 onunload 事件處理程序的方式。
第一種方式是使用 JavaScript:
EventUtil.addHandler(window, "unload", function(event){
alert("Unloaded");
});
指定事件處理程序的第二種方式,為 <body> 元素添加一個特性:
<!DOCTYPE html>
<html>
<head>
<title>Unload Event Example</title>
</head>
<body onunload="alert('Unloaded!')">
</body>
</html>
(3) resize 事件
當(dāng)瀏覽器窗口被調(diào)整到一個新的高度或?qū)挾葧r延欠,就會觸發(fā) resize 事件陌兑。可以通過 JavaScript 或者 <body> 元素中的 onresize 特性來指定事件處理程序由捎。
EventUtil.addHandler(window, "resize", function(event){
alert("Resized");
});
提示:瀏覽器窗口最小化或最大化時也會觸發(fā) resize 事件诀紊。
(4)scroll事件
雖然 scroll 事件是在 window 對象上發(fā)生的,但它實際表示的則是頁面中相應(yīng)元素的變化隅俘。
EventUtil.addHandler(window, "scroll", function(event) {
if (document.compatMode == "CSS1Compat") {
alert(document.documentElement.scrollTop);
} else {
alert(document.body.scrollTop);
}
});
2邻奠、焦點事件
焦點事件會在頁面元素獲得或失去焦點時觸發(fā)。
- blur :在元素失去焦點時觸發(fā)为居。這個事件不會冒泡碌宴;
- focus :在元素獲得焦點時觸發(fā)。這個事件不會冒泡蒙畴;
- focusin :在元素獲得焦點時觸發(fā)贰镣。這個事件與 HTML 事件 focus 等價,但它冒泡膳凝。
- focusout :在元素失去焦點時觸發(fā)碑隆。這個事件是 HTML 事件 blur 的通用版本。
最主要的兩個是 focus 和 blur 蹬音。
3上煤、鼠標與滾輪事件
DOM3 級事件中定義了 9 個鼠標事件:
- click :在用戶單擊主鼠標按鈕(一般是左邊的按鈕)或者按下回車鍵時觸發(fā)。
- dblclick :在用戶雙擊主鼠標按鈕(一般是左邊的按鈕)時觸發(fā)著淆。
- mousedown :在用戶按下了任意鼠標按鈕時觸發(fā)劫狠。
- mouseenter :在鼠標光標從元素外部首次移動到元素范圍之內(nèi)時觸發(fā)。
- mouseleave :在位于元素上方的鼠標光標移動到元素范圍之外時觸發(fā)永部。
- mousemove :當(dāng)鼠標指針在元素內(nèi)部移動時重復(fù)地觸發(fā)独泞。不能通過鍵盤觸發(fā)這個事件。
- mouseout :在鼠標指針位于一個元素上方苔埋,然后用戶將其移入另一個元素時觸發(fā)懦砂。又移入的另一個元素可能位于前一個元素的外部,也可能是這個元素的子元素组橄。不能通過鍵盤觸發(fā)這個事件荞膘。
- mouseover :在鼠標指針位于一個元素外部,然后用戶將其首次移入另一個元素邊界之內(nèi)時觸發(fā)晨炕。不能通過鍵盤觸發(fā)這個事件衫画。
- mouseup :在用戶釋放鼠標按鈕時觸發(fā)。不能通過鍵盤觸發(fā)這個事件瓮栗。
除了 mouseenter 和 mouseleave 削罩,所有鼠標事件都會冒泡瞄勾,也可以被取消,而取消鼠標事件將會影響瀏覽器的默認行為弥激。
只有在同一個元素上相繼觸發(fā) mousedown 和 mouseup 事件进陡,才會觸發(fā) click 事件;如果mousedown 或 mouseup 中的一個被取消微服,就不會觸發(fā) click 事件趾疚。
(1)客戶區(qū)坐標位置
鼠標事件都是在瀏覽器視口中的特定位置上發(fā)生的。這個位置信息保存在事件對象的 clientX 和clientY 屬性中以蕴。所有瀏覽器都支持這兩個屬性糙麦,它們的值表示事件發(fā)生時鼠標指針在視口中的水平和垂直坐標。
取得鼠標事件的客戶端坐標信息:
var div = document.getElementById("myDiv");
EventUtil.addHandler(div, "click", function(event){
event = EventUtil.getEvent(event);
alert("Client coordinates: " + event.clientX + "," + event.clientY);
});
(2)頁面坐標位置
頁面坐標通過事件對象的 pageX 和pageY 屬性丛肮,能告訴你事件是在頁面中的什么位置發(fā)生的赡磅。換句話說,這兩個屬性表示鼠標光標在頁面中的位置宝与,因此坐標是從頁面本身而非視口的左邊和頂邊計算的焚廊。
取得鼠標事件在頁面中的坐標:
var div = document.getElementById("myDiv");
EventUtil.addHandler(div, "click", function(event){
event = EventUtil.getEvent(event);
alert("Page coordinates: " + event.pageX + "," + event.pageY);
});
IE8 及更早版本不支持事件對象上的頁面坐標,可以使用客戶區(qū)坐標和滾動信息可以計算出來习劫。
var div = document.getElementById("myDiv");
EventUtil.addHandler(div, "click", function(event) {
event = EventUtil.getEvent(event);
var pageX = event.pageX,
pageY = event.pageY;
if (pageX === undefined) {
pageX = event.clientX + (document.body.scrollLeft ||
document.documentElement.scrollLeft);
}
if (pageY === undefined) {
pageY = event.clientY + (document.body.scrollTop ||
document.documentElement.scrollTop);
}
alert("Page coordinates: " + pageX + "," + pageY);
});
(3)屏幕坐標位置
鼠標事件發(fā)生時咆瘟,不僅會有相對于瀏覽器窗口的位置,還有一個相對于整個電腦屏幕的位置诽里。而通過 screenX 和 screenY 屬性就可以確定鼠標事件發(fā)生時鼠標指針相對于整個屏幕的坐標信息袒餐。
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 和 Meta(在 Windows鍵盤中是 Windows鍵匿乃,在蘋果機中是 Cmd 鍵),它們經(jīng)常被用來修改鼠標事件的行為豌汇。DOM 為此規(guī)定了 4 個屬性,表示這些修改鍵的狀態(tài): shiftKey 泄隔、 ctrlKey 拒贱、 altKey 和 metaKey 。這些屬性中包含的都是布爾值佛嬉,如果相應(yīng)的鍵被按下了逻澳,則值為 true ,否則值為 false 暖呕。
檢測不同修改鍵的狀態(tài):
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(","));
});
(5)鼠標按鈕
只有在主鼠標按鈕被單擊(或鍵盤回車鍵被按下)時才會觸發(fā) click 事件斜做,因此檢測按鈕的信息并不是必要的。
DOM 的 button 屬性可能有如下 3 個值: 0 表示主鼠標按鈕湾揽, 1 表示中間的鼠標按鈕(鼠標滾輪按鈕)瓤逼, 2 表示次鼠標按鈕笼吟。
(6)鼠標滾輪事件
當(dāng)用戶通過鼠標滾輪與頁面交互、在垂直方向上滾動頁面時(無論向上還是向下)霸旗,就會觸發(fā) mousewheel事件。
IE 6.0 首先實現(xiàn)了 mousewheel 事件。此后搓译,Opera吠架、Chrome 和 Safari 也都實現(xiàn)了這個事件。
與 mousewheel 事件對應(yīng)的 event 對象除包含鼠標事件的所有標準信息外精居,還包含一個特殊的 wheelDelta 屬性锄禽。當(dāng)用戶向前滾動鼠標滾輪時, wheelDelta 是 120 的倍數(shù)靴姿;當(dāng)用戶向后滾動鼠標滾輪時沃但, wheelDelta 是-120 的倍數(shù)。
EventUtil.addHandler(document, "mousewheel", function(event){
event = EventUtil.getEvent(event);
alert(event.wheelDelta);
});
Firefox 支持一個名為 DOMMouseScroll 的類似事件空猜,也是在鼠標滾輪滾動時觸發(fā)绽慈。有關(guān)鼠標滾輪的信息則保存在 detail 屬性中,當(dāng)向前滾動鼠標滾輪時辈毯,這個屬性的值是 -3 的倍數(shù)坝疼,當(dāng)向后滾動鼠標滾輪時,這個屬性的值是 3 的倍數(shù)谆沃。
EventUtil.addHandler(window, "DOMMouseScroll", function(event){
event = EventUtil.getEvent(event);
alert(event.detail);
});
跨瀏覽器環(huán)境下的解決方案:
var EventUtil = {
//省略了其他代碼
getWheelDelta: function(event) {
if (event.wheelDelta) {
return (client.engine.opera && client.engine.opera < 9.5 ?
-event.wheelDelta : event.wheelDelta);
} else {
return -event.detail * 40;
}
},
//省略了其他代碼
};
getWheelDelta() 方法首先檢測了事件對象是否包含 wheelDelta 屬性钝凶,如果是則通過瀏覽器檢測代碼確定正確的值。如果 wheelDelta 不存在唁影,則假設(shè)相應(yīng)的值保存在 detail 屬性中耕陷。由于Firefox 的值有所不同,因此首先要將這個值的符號反向据沈,然后再乘以 40哟沫,就可以保證與其他瀏覽器的值相同了。
使用示例
(function() {
function handleMouseWheel(event) {
event = EventUtil.getEvent(event);
var delta = EventUtil.getWheelDelta(event);
alert(delta);
}
EventUtil.addHandler(document, "mousewheel", handleMouseWheel);
EventUtil.addHandler(document, "DOMMouseScroll", handleMouseWheel);
})();
4锌介、鍵盤與文本事件
用戶在使用鍵盤時會觸發(fā)鍵盤事件嗜诀。
有 3 個鍵盤事件:
- keydown :當(dāng)用戶按下鍵盤上的任意鍵時觸發(fā),而且如果按住不放的話孔祸,會重復(fù)觸發(fā)此事件隆敢。
- keypress :當(dāng)用戶按下鍵盤上的字符鍵時觸發(fā),而且如果按住不放的話崔慧,會重復(fù)觸發(fā)此事件拂蝎。
- keyup :當(dāng)用戶釋放鍵盤上的鍵時觸發(fā)。
雖然所有元素都支持以上 3 個事件惶室,但只有在用戶通過文本框輸入文本時才最常用到温自。
只有一個文本事件: textInput 玄货。這個事件是對 keypress 的補充,用意是在將文本顯示給用戶之前更容易攔截文本捣作。在文本插入文本框之前會觸發(fā) textInput 事件誉结。
在用戶按了一下鍵盤上的字符鍵時,首先會觸發(fā) keydown 事件券躁,然后緊跟著是 keypress 事件惩坑,最后會觸發(fā) keyup 事件。其中也拜, keydown 和keypress 都是在文本框發(fā)生變化之前被觸發(fā)的以舒;而 keyup事件則是在文本框已經(jīng)發(fā)生變化之后被觸發(fā)的。如果用戶按下了一個字符鍵不放慢哈,就會重復(fù)觸發(fā)keydown 和 keypress 事件蔓钟,直到用戶松開該鍵為止。
(1)鍵碼
在發(fā)生 keydown 和 keyup 事件時卵贱, event 對象的 keyCode 屬性中會包含一個代碼滥沫,與鍵盤上一個特定的鍵對應(yīng)。
(2)字符編碼
發(fā)生 keypress 事件意味著按下的鍵會影響到屏幕中文本的顯示键俱。在所有瀏覽器中兰绣,按下能夠插入或刪除字符的鍵都會觸發(fā) keypress 事件。
charCode 屬性只有在發(fā)生keypress 事件時才包含值编振,而且這個值是按下的那個鍵所代表字符的 ASCII 編碼缀辩。
5、HTML5事件
(1) contextmenu 事件
contextmenu 事件用以表示何時應(yīng)該顯示上下文菜單踪央,以便開發(fā)人員取消默認的上下文菜單而提供自定義的菜單臀玄。
由于 contextmenu 事件是冒泡的,因此可以為 document 指定一個事件處理程序畅蹂,用以處理頁面中發(fā)生的所有此類事件健无。這個事件的目標是發(fā)生用戶操作的元素。
通常使用 contextmenu 事件來顯示自定義的上下文菜單液斜,而使用 onclick 事件處理程序來隱藏該菜單睬涧。
HTML結(jié)構(gòu):
<!DOCTYPE html>
<html>
<head>
<title>ContextMenu Event Example</title>
</head>
<body>
<div id="myDiv">Right click or Ctrl+click me to get a custom context menu. Click anywhere else to get the default context menu.</div>
<ul id="myMenu" style="position:absolute;visibility:hidden;background-color:
silver">
<li><a >Nicholas’ site</a></li>
<li><a >Wrox site</a></li>
<li><a >Yahoo!</a></li>
</ul>
</body>
</html>
JS 部分代碼:
EventUtil.addHandler(window, "load", function(event) {
var div = document.getElementById("myDiv");
EventUtil.addHandler(div, "contextmenu", function(event) {
event = EventUtil.getEvent(event);
EventUtil.preventDefault(event);
var menu = document.getElementById("myMenu");
menu.style.left = event.clientX + "px";
menu.style.top = event.clientY + "px";
menu.style.visibility = "visible";
});
EventUtil.addHandler(document, "click", function(event) {
document.getElementById("myMenu").style.visibility = "hidden";
});
});
為 <div> 元素添加了 oncontextmenu 事件的處理程序。這個事件處理程序首先會取消默認行為旗唁,以保證不顯示瀏覽器默認的上下文菜單。然后痹束,再根據(jù) event 對象 clientX 和clientY 屬性的值检疫,來確定放置 <ul> 元素的位置。最后一步就是通過將 visibility 屬性設(shè)置為"visible" 來顯示自定義上下文菜單祷嘶。另外屎媳,還為 document 添加了一個 onclick 事件處理程序夺溢,以便用戶能夠通過鼠標單擊來隱藏菜單(單擊也是隱藏系統(tǒng)上下文菜單的默認操作)。
雖然這個例子很簡單烛谊,但它卻展示了 Web 上所有自定義上下文菜單的基本結(jié)構(gòu)风响。
(2)beforeunload 事件
這個事件會在瀏覽器卸載頁面之前觸發(fā),可以通過它來取消卸載并繼續(xù)使用原有頁面丹禀。
(3)DOMContentLoaded 事件
window 的 load 事件會在頁面中的一切都加載完畢時觸發(fā)状勤,但這個過程可能會因為要加載的外部資源過多而頗費周折。而 DOMContentLoaded 事件則在形成完整的 DOM樹之后就會觸發(fā)双泪,不理會圖像持搜、JavaScript 文件、CSS 文件或其他資源是否已經(jīng)下載完畢焙矛。與 load 事件不同葫盼,DOMContentLoaded 支持在頁面下載的早期添加事件處理程序,這也就意味著用戶能夠盡早地與頁面進行交互村斟。
要處理 DOMContentLoaded 事件贫导,可以為 document 或 window 添加相應(yīng)的事件處理程序(盡管這個事件會冒泡到 window ,但它的目標實際上是 document )蟆盹。
EventUtil.addHandler(document, "DOMContentLoaded", function(event){
alert("Content loaded");
});
DOMContentLoaded 事件對象不會提供任何額外的信息(其 target 屬性是 document )孩灯。
通常這個事件既可以添加事件處理程序,也可以執(zhí)行其他 DOM 操作日缨。這個事件始終都會在 load 事件之前觸發(fā)钱反。
(4) readystatechange 事件
IE 為 DOM 文檔中的某些部分提供了 readystatechange 事件。這個事件的目的是提供與文檔或元素的加載狀態(tài)有關(guān)的信息匣距,但這個事件的行為有時候也很難預(yù)料面哥。支持 readystatechange 事件的每個對象都有一個 readyState 屬性,可能包含下列 5 個值中的一個毅待。
- uninitialized (未初始化):對象存在但尚未初始化尚卫。
- loading (正在加載):對象正在加載數(shù)據(jù)。
- loaded (加載完畢):對象加載數(shù)據(jù)完成尸红。
- interactive (交互):可以操作對象了吱涉,但還沒有完全加載。
- complete (完成):對象已經(jīng)加載完畢外里。
并非所有對象都會經(jīng)歷 readyState 的這幾個階段怎爵。
同時檢測交互和完成階段:
EventUtil.addHandler(document, "readystatechange", function(event){
if (document.readyState == "interactive" || document.readyState == "complete"){
EventUtil.removeHandler(document, "readystatechange",arguments.callee);
alert("Content loaded");
}
});
由于事件處理程序使用的是匿名函數(shù),因此使用了 arguments.callee 來引用該函數(shù)盅蝗。
(5) pageshow 和 pagehide 事件
Firefox 和 Opera 有一個特性鳖链,名叫“往返緩存”(back-forward cache,或 bfcache)墩莫,可以在用戶使用瀏覽器的“后退”和“前進”按鈕時加快頁面的轉(zhuǎn)換速度芙委。這個緩存中不僅保存著頁面數(shù)據(jù)逞敷,還保存了 DOM 和 JavaScript 的狀態(tài);實際上是將整個頁面都保存在了內(nèi)存里灌侣。
pageshow 事件在頁面顯示時觸發(fā)推捐,無論該頁面是否來自 bfcache。在重新加載的頁面中侧啼, pageshow 會在 load 事件觸發(fā)后觸發(fā)牛柒;而對于 bfcache 中的頁面, pageshow 會在頁面狀態(tài)完全恢復(fù)的那一刻觸發(fā)慨菱。另外要注意的是焰络,雖然這個事件的目標是 document ,但必須將其事件處理程序添加到 window 符喝。
pageshow 事件的 event 對象還包含一個名為 persisted 的布爾值屬性闪彼。
如果頁面被保存在了 bfcache 中,則這個屬性的值為 true 协饲;否則畏腕,這個屬性的值為 false 。
(function() {
var showCount = 0;
EventUtil.addHandler(window, "load", function() {
alert("Load fired");
});
EventUtil.addHandler(window, "pageshow", function() {
showCount++;
alert("Show has been fired " + showCount +
" times. Persisted? " + event.persisted);
});
})();
通過檢測 persisted 屬性茉稠,就可以根據(jù)頁面在 bfcache 中的狀態(tài)來確定是否需要采取其他操作描馅。
與 pageshow 事件對應(yīng)的是 pagehide 事件,該事件會在瀏覽器卸載頁面的時候觸發(fā)而线,而且是在unload 事件之前觸發(fā)铭污。與 pageshow 事件一樣, pagehide 在 document 上面觸發(fā)膀篮,但其事件處理程序必須要添加到 window 對象嘹狞。這個事件的 event 對象也包含 persisted 屬性,不過其用途稍有不同誓竿。
對于 pagehide 事件磅网,如果頁面在卸載之后會被保存在 bfcache 中,那么 persisted 的值也會被設(shè)置為 true 筷屡。因此涧偷,當(dāng)?shù)谝淮斡|發(fā) pageshow 時, persisted 的值一定是 false毙死。
提示:指定了 onunload 事件處理程序的頁面會被自動排除在 bfcache 之外燎潮,即使事件處理程序是空的。原因在于扼倘, onunload 最常用于撤銷在 onload 中所執(zhí)行的操作跟啤,而跳過 onload 后再次顯示頁面很可能就會導(dǎo)致頁面不正常。
(6)hashchange 事件
HTML5 新增了 hashchange 事件,以便在 URL 的參數(shù)列表(及 URL 中“#”號后面的所有字符串)發(fā)生變化時通知開發(fā)人員隅肥。之所以新增這個事件,是因為在 Ajax 應(yīng)用中袄简,開發(fā)人員經(jīng)常要利用 URL 參數(shù)列表來保存狀態(tài)或?qū)Ш叫畔ⅰ?/p>
必須要把 hashchange 事件處理程序添加給 window 對象腥放,然后 URL 參數(shù)列表只要變化就會調(diào)用它。此時的 event 對象應(yīng)該額外包含兩個屬性: oldURL 和 newURL 绿语。這兩個屬性分別保存著參數(shù)列表變化前后的完整 URL秃症。
EventUtil.addHandler(window, "hashchange", function(event){
alert("Old URL: " + event.oldURL + "\nNew URL: " + event.newURL);
});
只有 Firefox 6+、Chrome 和 Opera 支持 oldURL 和 newURL 屬性吕粹。為此种柑,最好是使用 location對象來確定當(dāng)前的參數(shù)列表。
EventUtil.addHandler(window, "hashchange", function(event){
alert("Current hash: " + location.hash);
});
檢測瀏覽器是否支持 hashchange 事件:
var isSupported = ("onhashchange" in window) && (document.documentMode ===
undefined || document.documentMode > 7);
6匹耕、觸摸與手勢事件
(1)觸摸事件
觸摸事件會在用戶手指放在屏幕上面時聚请、在屏幕上滑動時或從屏幕上移開時觸發(fā)。
- touchstart :當(dāng)手指觸摸屏幕時觸發(fā)稳其;即使已經(jīng)有一個手指放在了屏幕上也會觸發(fā)驶赏。
- touchmove :當(dāng)手指在屏幕上滑動時連續(xù)地觸發(fā)。在這個事件發(fā)生期間既鞠,調(diào)用 preventDefault()可以阻止?jié)L動煤傍。
- touchend :當(dāng)手指從屏幕上移開時觸發(fā)。
- touchcancel :當(dāng)系統(tǒng)停止跟蹤觸摸時觸發(fā)嘱蛋。
這幾個事件都會冒泡蚯姆,也都可以取消。每個觸摸事件的 event 對象都提供了在鼠標事件中常見的屬性:bubbles 洒敏、 cancelable 龄恋、 view 、 clientX 桐玻、 clientY 篙挽、 screenX 、 screenY 镊靴、 detail 铣卡、 altKey 、 shiftKey 偏竟、 ctrlKey
和 metaKey
煮落。
除了常見的 DOM屬性外,觸摸事件還包含三個用于跟蹤觸摸的屬性踊谋。
- touches :表示當(dāng)前跟蹤的觸摸操作的 Touch 對象的數(shù)組蝉仇。
- targetTouchs :特定于事件目標的 Touch 對象的數(shù)組。
- changeTouches :表示自上次觸摸以來發(fā)生了什么改變的 Touch 對象的數(shù)組。
每個 Touch 對象包含下列屬性轿衔。
- clientX :觸摸目標在視口中的 x 坐標沉迹。
- clientY :觸摸目標在視口中的 y 坐標。
- identifier :標識觸摸的唯一 ID害驹。
- pageX :觸摸目標在頁面中的 x 坐標鞭呕。
- pageY :觸摸目標在頁面中的 y 坐標。
- screenX :觸摸目標在屏幕中的 x 坐標宛官。
- screenY :觸摸目標在屏幕中的 y 坐標葫松。
- target :觸摸的 DOM 節(jié)點目標。
使用這些屬性可以跟蹤用戶對屏幕的觸摸操作底洗。
function handleTouchEvent(event) {
//只跟蹤一次觸摸
if (event.touches.length == 1) {
var output = document.getElementById("output");
switch (event.type) {
case "touchstart":
output.innerHTML = "Touch started (" + event.touches[0].clientX +
"," + event.touches[0].clientY + ")";
break;
case "touchend":
output.innerHTML += "<br>Touch ended (" +
event.changedTouches[0].clientX + "," +
event.changedTouches[0].clientY + ")";
break;
case "touchmove":
event.preventDefault(); //阻止?jié)L動
output.innerHTML += "<br>Touch moved (" +
event.changedTouches[0].clientX + "," +
event.changedTouches[0].clientY + ")";
break;
}
}
}
EventUtil.addHandler(document, "touchstart", handleTouchEvent);
EventUtil.addHandler(document, "touchend", handleTouchEvent);
EventUtil.addHandler(document, "touchmove", handleTouchEvent);
(2)手勢事件
當(dāng)兩個手指觸摸屏幕時就會產(chǎn)生手勢腋么,手勢通常會改變顯示項的大小,或者旋轉(zhuǎn)顯示項亥揖。有三個手勢事件:
- gesturestart :當(dāng)一個手指已經(jīng)按在屏幕上而另一個手指又觸摸屏幕時觸發(fā)珊擂。
- gesturechange :當(dāng)觸摸屏幕的任何一個手指的位置發(fā)生變化時觸發(fā)。
- gestureend :當(dāng)任何一個手指從屏幕上面移開時觸發(fā)徐块。
只有兩個手指都觸摸到事件的接收容器時才會觸發(fā)這些事件未玻。
觸摸事件和手勢事件之間存在某種關(guān)系。當(dāng)一個手指放在屏幕上時胡控,會觸發(fā) touchstart 事件扳剿。如果另一個手指又放在了屏幕上,則會先觸發(fā) gesturestart 事件昼激,隨后觸發(fā)基于該手指的 touchstart事件庇绽。如果一個或兩個手指在屏幕上滑動,將會觸發(fā) gesturechange 事件橙困。但只要有一個手指移開瞧掺,就會觸發(fā) gestureend 事件,緊接著又會觸發(fā)基于該手指的 touchend 事件凡傅。
與觸摸事件一樣辟狈,每個手勢事件的 event 對象都包含著標準的鼠標事件屬性: bubbles 、cancelable 夏跷、 view 哼转、 clientX 、 clientY 槽华、 screenX 壹蔓、 screenY 、 detail 猫态、 altKey 佣蓉、 shiftKey 披摄、ctrlKey
和metaKey
。
還包含兩個額外的屬性: rotation 和 scale 勇凭。其中疚膊, rotation 屬性表
示手指變化引起的旋轉(zhuǎn)角度,負值表示逆時針旋轉(zhuǎn)套像,正值表示順時針旋轉(zhuǎn)(該值從 0 開始)酿联。而 scale屬性表示兩個手指間距離的變化情況(例如向內(nèi)收縮會縮短距離);這個值從 1 開始夺巩,并隨距離拉大而增長,隨距離縮短而減小周崭。
使用手勢事件的一個示例:
function handleGestureEvent(event) {
var output = document.getElementById("output");
switch (event.type) {
case "gesturestart":
output.innerHTML = "Gesture started (rotation=" + event.rotation +
",scale=" + event.scale + ")";
break;
case "gestureend":
output.innerHTML += "<br>Gesture ended (rotation=" + event.rotation +
",scale=" + event.scale + ")";
break;
case "gesturechange":
output.innerHTML += "<br>Gesture changed (rotation=" + event.rotation +
",scale=" + event.scale + ")";
break;
}
}
document.addEventListener("gesturestart", handleGestureEvent, false);
document.addEventListener("gestureend", handleGestureEvent, false);
document.addEventListener("gesturechange", handleGestureEvent, false);
五柳譬、內(nèi)存和性能
在 JavaScript 中,添加到頁面上的事件處理程序數(shù)量將直接關(guān)系到頁面的整體運行性能续镇。導(dǎo)致這一問題的原因是多方面的美澳。首先,每個函數(shù)都是對象摸航,都會占用內(nèi)存制跟;內(nèi)存中的對象越多,性能就越差酱虎。其次雨膨,必須事先指定所有事件處理程序而導(dǎo)致的 DOM訪問次數(shù),會延遲整個頁面的交互就緒時間读串。
1聊记、事件委托
對“事件處理程序過多”問題的解決方案就是事件委托。事件委托利用了事件冒泡恢暖,只指定一個事件處理程序排监,就可以管理某一類型的所有事件。
<ul id="myLinks">
<li id="goSomewhere">Go somewhere</li>
<li id="doSomething">Do something</li>
<li id="sayHi">Say hi</li>
</ul>
使用事件委托杰捂,只需在DOM 樹中盡量最高的層次上添加一個事件處理程序:
var list = document.getElementById("myLinks");
EventUtil.addHandler(list, "click", function(event) {
event = EventUtil.getEvent(event);
var target = EventUtil.getTarget(event);
switch (target.id) {
case "doSomething":
document.title = "I changed the document's title";
break;
case "goSomewhere":
location.;
break;
case "sayHi":
alert("hi");
break;
}
});
優(yōu)點:
- 在頁面中設(shè)置事件處理程序所需的時間更少舆床。只添加一個事件處理程序所需的 DOM引用更少,所花的時間也更少嫁佳。
- 整個頁面占用的內(nèi)存空間更少挨队,能夠提升整體性能。
最適合采用事件委托技術(shù)的事件包括 click 脱拼、 mousedown 瞒瘸、 mouseup 、 keydown 熄浓、 keyup
和 keypress
情臭。
2省撑、移除事件處理程序
每當(dāng)將事件處理程序指定給元素時,運行中的瀏覽器代碼與支持頁面交互的 JavaScript 代碼之間就會建立一個連接俯在。這種連接越多竟秫,頁面執(zhí)行起來就越慢。
內(nèi)存中留有那些過時不用的“空事件處理程序”(dangling event handler)跷乐,也是造成 Web 應(yīng)用程序內(nèi)存與性能問題的主要原因肥败。
如果你知道某個元素即將被移除,那么最好手工移除事件處理程序:
<div id="myDiv">
<input type="button" value="Click Me" id="myBtn">
</div>
<script type="text/javascript">
var btn = document.getElementById("myBtn");
btn.onclick = function() {
//先執(zhí)行某些操作
btn.onclick = null; // 移除事件處理程序
document.getElementById("myDiv").innerHTML = "Processing...";
};
</script>
注意愕提,在事件處理程序中刪除按鈕也能阻止事件冒泡馒稍。目標元素在文檔中是事件冒泡的前提。
在頁面卸載之前浅侨,先通過 onunload 事件處理程序移除所有事件處理程序纽谒。只要是通過 onload 事件處理程序添加的東西,最后都要通過 onunload 事件處理程序?qū)⑺鼈円瞥?/p>
六如输、模擬事件
事件鼓黔,就是網(wǎng)頁中某個特別值得關(guān)注的瞬間。事件經(jīng)常由用戶操作或通過其他瀏覽器功能來觸發(fā)不见。
1澳化、DOM中的事件模擬
可以在 document 對象上使用 createEvent() 方法創(chuàng)建 event 對象。這個方法接收一個參數(shù)稳吮,即表示要創(chuàng)建的事件類型的字符串缎谷。
在創(chuàng)建了 event 對象之后,還需要使用與事件有關(guān)的信息對其進行初始化盖高。每種類型的 event 對象都有一個特殊的方法慎陵,為它傳入適當(dāng)?shù)臄?shù)據(jù)就可以初始化該 event 對象。不同類型的這個方法的名字也不相同喻奥,具體要取決于 createEvent() 中使用的參數(shù)席纽。
模擬事件的最后一步就是觸發(fā)事件。這一步需要使用 dispatchEvent() 方法撞蚕,所有支持事件的DOM 節(jié)點都支持這個方法润梯。調(diào)用 dispatchEvent() 方法時,需要傳入一個參數(shù)甥厦,即表示要觸發(fā)事件的 event 對象纺铭。觸發(fā)事件之后,該事件就躋身“官方事件”之列了刀疙,因而能夠照樣冒泡并引發(fā)相應(yīng)事
件處理程序的執(zhí)行舶赔。
模擬鼠標事件
創(chuàng)建新的鼠標事件對象并為其指定必要的信息,就可以模擬鼠標事件谦秧。創(chuàng)建鼠標事件對象的方法是為 createEvent() 傳入字符串 "MouseEvents" 竟纳。返回的對象有一個名為 initMouseEvent() 方法撵溃,用于指定與該鼠標事件有關(guān)的信息。這個方法接收 15 個參數(shù)锥累,分別與鼠標事件中每個典型的屬性一一對應(yīng)缘挑;
- type (字符串):表示要觸發(fā)的事件類型,例如 "click" 桶略。
- bubbles (布爾值):表示事件是否應(yīng)該冒泡语淘。為精確地模擬鼠標事件,應(yīng)該把這個參數(shù)設(shè)置為true 际歼。
- cancelable (布爾值):表示事件是否可以取消惶翻。為精確地模擬鼠標事件,應(yīng)該把這個參數(shù)設(shè)置為 true 鹅心。
- view (AbstractView):與事件關(guān)聯(lián)的視圖维贺。這個參數(shù)幾乎總是要設(shè)置為 document.defaultView 。
- detail (整數(shù)):與事件有關(guān)的詳細信息巴帮。這個值一般只有事件處理程序使用,但通常都設(shè)置為 0 虐秋。
- screenX (整數(shù)):事件相對于屏幕的 X 坐標榕茧。
- screenY (整數(shù)):事件相對于屏幕的 Y 坐標。
- clientX (整數(shù)):事件相對于視口的 X 坐標客给。
- clientY (整數(shù)):事件想對于視口的 Y 坐標用押。
- ctrlKey (布爾值):表示是否按下了 Ctrl 鍵。默認值為 false 靶剑。
- altKey (布爾值):表示是否按下了 Alt 鍵蜻拨。默認值為 false 。
- shiftKey (布爾值):表示是否按下了 Shift 鍵桩引。默認值為 false 缎讼。
- metaKey (布爾值):表示是否按下了 Meta 鍵。默認值為 false 坑匠。
- button (整數(shù)):表示按下了哪一個鼠標鍵血崭。默認值為 0 。
- relatedTarget (對象):表示與事件相關(guān)的對象厘灼。這個參數(shù)只在模擬 mouseover 或 mouseout時使用
前 4 個參數(shù)對正確地激發(fā)事件至關(guān)重要夹纫,因為瀏覽器要用到這些參數(shù);
var btn = document.getElementById("myBtn");
//創(chuàng)建事件對象
var event = document.createEvent("MouseEvents");
//初始化事件對象
event.initMouseEvent("click", true, true, document.defaultView, 0, 0, 0, 0, 0,
false, false, false, false, 0, null);
//觸發(fā)事件
btn.dispatchEvent(event);
同樣设凹,對于鍵盤事件舰讹、IE中的事件模擬和其他事件也可以模擬,也可以自定義 DOM 事件闪朱。