1### Menu
第13章 事 件
13.2 事件處理程序
- 13.2.1 HTML事件處理程序
- 13.2.2 DOM0 級(jí)事件處理程序
- 13.2.3 DOM2 級(jí)事件處理程序
- 13.2.4 IE事件處理程序
- 13.2.5 跨瀏覽器的事件處理程序
13.3 事件對(duì)象
- 13.3.1 DOM中的事件對(duì)象
13.4 事件類型
- 13.4.1 UI事件
- 13.4.2 焦點(diǎn)事件
- 13.4.3 鼠標(biāo)與滾輪事件
- 13.4.4 鍵盤與文本事件
- 13.4.6 變動(dòng)事件
- 13.4.7 HTML5 事件
13.5 內(nèi)存和性能
- 13.5.1 事件委托
- 13.5.2 移除事件處理程序
13.6 模擬事件
- 13.6.1 DOM中的事件模擬
第13章 事 件
13.2 事件處理程序
13.2.1 HTML事件處理程序
<input type="button" value="Click Me" onclick="alert('Clicked')" />
- 這個(gè)操作是通過指定 onclick 特性并將一些 JavaScript
代碼作為它的值來定義的。由于這個(gè)值是 JavaScript,因此不能在其中使用未經(jīng)轉(zhuǎn)義的 HTML 語法字符豆混,例如和號(hào)(&)樟插、雙引號(hào)("")验夯、小于號(hào)(<)或大于號(hào)(>)芦圾。為了避免使用 HTML 實(shí)體昔案,這里使用了單引號(hào)乒验。如果想要使用雙引號(hào)愚隧,那么就要將代碼改寫成如下所示:
<input type="button" value="Click Me" onclick="alert("Clicked")" />
- 在 HTML 中定義的事件處理程序可以包含要執(zhí)行的具體動(dòng)作,也可以調(diào)用在頁面其他地方定義的腳本锻全,如下面的例子所示
<script type="text/javascript">
function showMessage(){
alert("Hello world!");
}
</script>
<input type="button" value="Click Me" onclick="showMessage()" />
13.2.2 DOM0 級(jí)事件處理程序
- 使用 DOM0 級(jí)方法指定的事件處理程序被認(rèn)為是元素的方法狂塘。因此,這時(shí)候的事件處理程序是在
元素的作用域中運(yùn)行鳄厌;換句話說荞胡,程序中的 this 引用當(dāng)前元素。來看一個(gè)例子了嚎。
<body>
<button id="myBtn">click me11.</button>
<script>
var btn = document.getElementById("myBtn");
btn.onclick = function(){
this.style.color = "red"; //"myBtn"
};
</script>
- 單擊按鈕泪漂,button的字體會(huì)變成紅色,this就代表當(dāng)前操作的元素歪泳;
- 也可以刪除通過 DOM0 級(jí)方法指定的事件處理程序萝勤;
btn.onclick = null; //刪除事件處理程序
13.2.3 DOM2 級(jí)事件處理程序
- “ DOM2 級(jí)事件” 定義了兩個(gè)方法,用于處理指定和刪除事件處理程序的操作: addEventListener()和 removeEventListener()呐伞。所有 DOM 節(jié)點(diǎn)中都包含這兩個(gè)方法敌卓,并且它們都接受 3 個(gè)參數(shù)(“時(shí)間名”,處理事件程序伶氢,一個(gè)布爾值)假哎,最后這個(gè)布爾值參數(shù)如果是 true,表示在捕獲階段調(diào)用事件處理程序鞍历;如果是 false,表示在冒泡階段調(diào)用事件處理程序(布爾值最好填false)肪虎。 代碼如下:
var btn = document.getElementById("myBtn");
btn.addEventListener("click", function(){
alert(this.id);
}, false);
- 使用 DOM2 級(jí)方法添加事件處理程序的主要好處是可以添加多個(gè)事件處理程序劣砍。
// 會(huì)按順序觸發(fā),先alert“mybtn”扇救,再alert“hello world”
var btn = document.getElementById("myBtn");
btn.addEventListener("click", function(){
alert(this.id);
}, false);
btn.addEventListener("click", function(){
alert("Hello world!");
}, false);
-
removeEventListener()
removeEventListener()中的事件處理程序函數(shù)必須與傳入
addEventListener()中的相同刑枝,如果用匿名函數(shù)的話就無法移除香嗓;
有效例子如下:
var btn = document.getElementById("myBtn");
var handler = function(){
alert(this.id);
};
btn.addEventListener("click", handler, false);
//這里省略了其他代碼
btn.removeEventListener("click", handler, false); //有效!
</script>
- 大多數(shù)情況下装畅,都是將事件處理程序添加到事件流的冒泡階段靠娱,這樣可以最大限度地兼容各種瀏覽器。最好只在需要在事件到達(dá)目標(biāo)之前截獲它的時(shí)候?qū)⑹录幚沓绦蛱砑拥讲东@階段掠兄。如果不是特別需
要像云,我們不建議在事件捕獲階段注冊事件處理程序。
- 13.2.5 跨瀏覽器的事件處理程序
- 第一個(gè)要?jiǎng)?chuàng)建的方法是 addHandler()蚂夕,它的職責(zé)是視情況分別使用 DOM0 級(jí)方法迅诬、 DOM2 級(jí)方法,這個(gè)方法屬于一個(gè)名叫 EventUtil 的對(duì)象婿牍,本書將使用這個(gè)對(duì)象來處理瀏覽器間的差異侈贷。addHandler()方法接受 3 個(gè)參數(shù):要操作的元素、事件名稱和事件處理程序函數(shù)等脂。
- 這兩個(gè)方法首先都會(huì)檢測傳入的元素中是否存在 DOM2 級(jí)方法俏蛮。如果存在 DOM2 級(jí)方法,則使用該方法:傳入事件類型上遥、事件處理程序函數(shù)和第三個(gè)參數(shù) false(表示冒泡階段)搏屑。注意,為了在 IE8 及更早版本中運(yùn)行露该,此時(shí)的事件類型必須加上"on"前綴睬棚。
最后一種可能就是使用 DOM0 級(jí)方法(在現(xiàn)代瀏覽器中,應(yīng)該不會(huì)執(zhí)行這里的代碼)解幼。此時(shí)抑党,我們使用的是方括號(hào)語法來將屬性名指定為事件處理程序,或者將屬性設(shè)置為 null撵摆。
var EventUtil = {
addHandler: function(element, type, handler){
if (element.addEventListener){
element.addEventListener(type, handler, false);
} else {
element["on" + type] = handler;
}
},
removeHandler: function(element, type, handler){
if (element.removeEventListener){
element.removeEventListener(type, handler, false);
} else {
element["on" + type] = null;
}
}
};
- 可以像下面這樣使用 EventUtil 對(duì)象:
var btn = document.getElementById("myBtn");
var handler = function(){
alert("Clicked");
};
EventUtil.addHandler(btn, "click", handler);
//這里省略了其他代碼
EventUtil.removeHandler(btn, "click", handler);
13.3 事件對(duì)象
- 13.3.1 DOM中的事件對(duì)象
- 兼容 DOM 的瀏覽器會(huì)將一個(gè) event 對(duì)象傳入到事件處理程序中底靠。無論指定事件處理程序時(shí)使用什么方法(DOM0 級(jí)或 DOM2 級(jí)) ,都會(huì)傳入 event 對(duì)象特铝。來看下面的例子暑中。
var btn = document.getElementById("myBtn");
btn.onclick = function(event){
alert(event.type); //"click"
};
btn.addEventListener("click", function(event){
alert(event.type); //"click"
}, false);
-
event 對(duì)象包含與創(chuàng)建它的特定事件有關(guān)的屬性和方法。觸發(fā)的事件類型不一樣鲫剿,可用的屬性和方法也不一樣鳄逾。不過,所有事件都會(huì)有下表列出的成員灵莲。
event的屬性和方法
event的屬性和方法 最新的屬性和方法去w3c看雕凹;
在事件處理程序內(nèi)部,對(duì)象 this 始終等于 currentTarget 的值,而 target 則只包含事件的實(shí)際目標(biāo)枚抵。如果直接將事件處理程序指定給了目標(biāo)元素线欲,則 this、 currentTarget 和 target 包含相同的值汽摹。來看下面的例子李丰。
var btn = document.getElementById("myBtn");
btn.onclick = function(event){
alert(event.currentTarget === this); //true
alert(event.target === this); //true
};
- 這個(gè)例子檢測了 currentTarget 和 target 與 this 的值。由于 click 事件的目標(biāo)是按鈕逼泣,因此這三個(gè)值是相等的趴泌。如果事件處理程序存在于按鈕的父節(jié)點(diǎn)中(例如 document.body),那么這些值是不相同的圾旨。再看下面的例子踱讨。
document.body.onclick = function(event){
alert(event.currentTarget === document.body); //true
alert(this === document.body); //true
alert(event.target === document.getElementById("myBtn")); //true
};
- 在需要通過一個(gè)函數(shù)處理多個(gè)事件時(shí),可以使用 type 屬性砍的。例如:
<button id="myBtn">click me11.</button>
<script>
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;
</script>
- 只有 cancelable 屬性設(shè)置為 true 的事件痹筛,才可以使用 preventDefault()來取消其默認(rèn)行為。
- 要阻止特定事件的默認(rèn)行為廓鞠,可以使用 preventDefault()方法帚稠。例如,鏈接的默認(rèn)行為就是在被單擊時(shí)會(huì)導(dǎo)航到其 href 特性指定的 URL床佳。如果你想阻止鏈接導(dǎo)航這一默認(rèn)行為滋早,那么通過鏈接的onclick 事件處理程序可以取消它,如下面的例子所示:
var link = document.getElementById("myLink");
link.onclick = function(event){
event.preventDefault();
};
- 另外砌们, stopPropagation()方法用于立即停止事件在 DOM 層次中的傳播杆麸,即取消進(jìn)一步的事件
捕獲或冒泡。例如浪感,直接添加到一個(gè)按鈕的事件處理程序可以調(diào)用 stopPropagation()昔头,從而避免觸
發(fā)注冊在 document.body 上面的事件處理程序,如下面的例子所示影兽。
var btn = document.getElementById("myBtn");
btn.onclick = function(event){
alert("Clicked");
// 調(diào)用后揭斧,阻止向上冒泡 body注冊的onclick就不會(huì)運(yùn)行了。
event.stopPropagation();
};
document.body.onclick = function(event){
alert("Body clicked");
};
- 事件對(duì)象的 eventPhase 屬性峻堰,可以用來確定事件當(dāng)前正位于事件流的哪個(gè)階段讹开。如果是在捕獲階段調(diào)用的事件處理程序,那么 eventPhase 等于 1捐名;如果事件處理程序處于目標(biāo)對(duì)象上旦万,則 eventPhase 等于 2;如果是在冒泡階段調(diào)用的事件處理程序镶蹋, eventPhase 等于 3成艘。這里要注意的是拇砰,盡管“處于目標(biāo)”發(fā)生在冒泡階段,但 eventPhase 仍然一直等于 2狰腌。來看下面的例子。
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
};
13.4 事件類型
- 13.4.1 UI事件
- UI 事件指的是那些不一定與用戶操作有關(guān)的事件牧氮。這些事件在 DOM 規(guī)范出現(xiàn)之前琼腔,都是以這種或
那種形式存在的,而在 DOM 規(guī)范中保留是為了向后兼容□飧穑現(xiàn)有的 UI 事件如下丹莲。- load:當(dāng)頁面完全加載后在 window 上面觸發(fā),當(dāng)所有框架都加載完畢時(shí)在框架集上面觸發(fā)尸诽,
當(dāng)圖像加載完畢時(shí)在<img>元素上面觸發(fā)甥材,或者當(dāng)嵌入的內(nèi)容加載完畢時(shí)在<object>元素上面
觸發(fā)。 - unload 事件:與 load 事件對(duì)應(yīng)的是 unload 事件性含,這個(gè)事件在文檔被完全卸載后觸發(fā)洲赵。只要用戶從一個(gè)頁面切換到另一個(gè)頁面,就會(huì)發(fā)生 unload 事件商蕴。而利用這個(gè)事件最多的情況是清除引用叠萍,以避免內(nèi)存泄漏。
- resize 事件:當(dāng)瀏覽器窗口被調(diào)整到一個(gè)新的高度或?qū)挾葧r(shí)绪商,就會(huì)觸發(fā) resize 事件苛谷。這個(gè)事件在 window(窗口)上面觸發(fā),因此可以通過 JavaScript 或者<body>元素中的 onresize 特性來指定事件處理程序格郁。
- load:當(dāng)頁面完全加載后在 window 上面觸發(fā),當(dāng)所有框架都加載完畢時(shí)在框架集上面觸發(fā)尸诽,
function myResize(event){
li.innerHTML = document.documentElement.clientWidth +" " + document.documentElement.clientHeight // 顯示現(xiàn)在的窗口clientSize
}
document.body.onresize = myResize;
- scroll 事件:雖然 scroll 事件是在 window 對(duì)象上發(fā)生的腹殿,但它實(shí)際表示的則是頁面中相應(yīng)元素的變化。在混雜模式下例书,可以通過<body>元素的 scrollLeft 和 scrollTop 來監(jiān)控到這一變化锣尉;
- 13.4.2 焦點(diǎn)事件
- 焦點(diǎn)事件會(huì)在頁面元素獲得或失去焦點(diǎn)時(shí)觸發(fā)。利用這些事件并與 document.hasFocus()方法及document.activeElement 屬性配合雾叭,可以知曉用戶在頁面上的行蹤悟耘。有以下 6 個(gè)焦點(diǎn)事件。
- blur:在元素失去焦點(diǎn)時(shí)觸發(fā)织狐。這個(gè)事件不會(huì)冒泡暂幼;所有瀏覽器都支持它。
- focus:在元素獲得焦點(diǎn)時(shí)觸發(fā)移迫。這個(gè)事件不會(huì)冒泡旺嬉;所有瀏覽器都支持它
- focusin:在元素獲得焦點(diǎn)時(shí)觸發(fā)。這個(gè)事件與 HTML 事件 focus 等價(jià)厨埋,但它冒泡邪媳。
- focusout:在元素失去焦點(diǎn)時(shí)觸發(fā)。這個(gè)事件是 HTML 事件 blur 的通用版本。
- 要確定瀏覽器是否支持這些事件雨效,可以使用如下代碼:
var isSupported = document.implementation.hasFeature("FocusEvent", "3.0");
13.4.3 鼠標(biāo)與滾輪事件
要檢測瀏覽器是否支持上面的所有事件迅涮,可以使用以下代碼:
var isSupported = document.implementation.hasFeature("MouseEvent", "3.0")click:在用戶單擊主鼠標(biāo)按鈕(一般是左邊的按鈕)或者按下回車鍵時(shí)觸發(fā)。這一點(diǎn)對(duì)確保
易訪問性很重要徽龟,意味著 onclick 事件處理程序既可以通過鍵盤也可以通過鼠標(biāo)執(zhí)行叮姑。dblclick:在用戶雙擊主鼠標(biāo)按鈕(一般是左邊的按鈕)時(shí)觸發(fā)。從技術(shù)上說据悔,這個(gè)事件并不
是 DOM2 級(jí)事件規(guī)范中規(guī)定的传透,但鑒于它得到了廣泛支持,所以 DOM3 級(jí)事件將其納入了標(biāo)準(zhǔn)极颓。mousedown:在用戶按下了任意鼠標(biāo)按鈕時(shí)觸發(fā)朱盐。不能通過鍵盤觸發(fā)這個(gè)事件。
mouseenter:在鼠標(biāo)光標(biāo)從元素外部首次移動(dòng)到元素范圍之內(nèi)時(shí)觸發(fā)菠隆。這個(gè)事件不冒泡兵琳,而且
在光標(biāo)移動(dòng)到后代元素上不會(huì)觸發(fā)。 DOM2 級(jí)事件并沒有定義這個(gè)事件浸赫,但 DOM3 級(jí)事件將它
納入了規(guī)范闰围。 IE、 Firefox 9+和 Opera 支持這個(gè)事件既峡。mouseleave:在位于元素上方的鼠標(biāo)光標(biāo)移動(dòng)到元素范圍之外時(shí)觸發(fā)羡榴。這個(gè)事件不冒泡,而且
在光標(biāo)移動(dòng)到后代元素上不會(huì)觸發(fā)运敢。 DOM2 級(jí)事件并沒有定義這個(gè)事件校仑,但 DOM3 級(jí)事件將它
納入了規(guī)范。 IE传惠、 Firefox 9+和 Opera 支持這個(gè)事件迄沫。mousemove:當(dāng)鼠標(biāo)指針在元素內(nèi)部移動(dòng)時(shí)重復(fù)地觸發(fā)。不能通過鍵盤觸發(fā)這個(gè)事件卦方。
mouseout:在鼠標(biāo)指針位于一個(gè)元素上方羊瘩,然后用戶將其移入另一個(gè)元素時(shí)觸發(fā)。又移入的另
一個(gè)元素可能位于前一個(gè)元素的外部盼砍,也可能是這個(gè)元素的子元素尘吗。不能通過鍵盤觸發(fā)這個(gè)事件。mouseover:在鼠標(biāo)指針位于一個(gè)元素外部浇坐,然后用戶將其首次移入另一個(gè)元素邊界之內(nèi)時(shí)觸
發(fā)睬捶。不能通過鍵盤觸發(fā)這個(gè)事件。mouseup:在用戶釋放鼠標(biāo)按鈕時(shí)觸發(fā)近刘。不能通過鍵盤觸發(fā)這個(gè)事件擒贸。
- 客戶區(qū)坐標(biāo)位置: 鼠標(biāo)事件都是在瀏覽器視口中的特定位置上發(fā)生的臀晃。這個(gè)位置信息保存在事件對(duì)象的 clientX 和 clientY 屬性中。
- 頁面坐標(biāo)位置: 通過事件對(duì)象的 pageX 和pageY 屬性介劫,能告訴你事件是在頁面中的什么位置發(fā)生的徽惋。
- 屏幕坐標(biāo)位置 : 通過 screenX 和 screenY 屬性就可以確定鼠標(biāo)事件發(fā)生時(shí)鼠標(biāo)指針相對(duì)于整個(gè)屏幕的坐標(biāo)信息。
function myCoor(event){
li.innerHTML = "client size = "+ event.clientX + " " + event.clientY + "<br>" +
" page size = " + event.pageX + " " + event.pageY + "<br>" +
" screen size = " + event.screenX + " " + event.screenY
}
- 修改鍵 : 雖然鼠標(biāo)事件主要是使用鼠標(biāo)來觸發(fā)的座韵,但在按下鼠標(biāo)時(shí)鍵盤上的某些鍵的狀態(tài)也可以影響到所要采取的操作寂曹。這些修改鍵就是 Shift、 Ctrl回右、 Alt 和 Meta(在 Windows 鍵盤中是 Windows 鍵,在蘋果機(jī)中
是 Cmd 鍵)漱挚,它們經(jīng)常被用來修改鼠標(biāo)事件的行為翔烁。 DOM 為此規(guī)定了 4 個(gè)屬性,表示這些修改鍵的狀
態(tài): shiftKey旨涝、 ctrlKey蹬屹、 altKey 和 metaKey。這些屬性中包含的都是布爾值白华,如果相應(yīng)的鍵被按
下了慨默,則值為 true,否則值為 false弧腥。當(dāng)某個(gè)鼠標(biāo)事件發(fā)生時(shí)厦取,通過檢測這幾個(gè)屬性就可以確定用戶
是否同時(shí)按下了其中的鍵。
function myClick(event){
li.innerHTML = "ctrl = " + String(event.ctrlKey) + " " + "shift =
" + String(event.shiftKey)+ " " + "microKey = " + String(event.metaKey)
}
- 相關(guān)元素 : 在發(fā)生 mouseover 和 mouserout 事件時(shí)管搪,還會(huì)涉及更多的元素虾攻。這兩個(gè)事件都會(huì)涉及把鼠標(biāo)指
針從一個(gè)元素的邊界之內(nèi)移動(dòng)到另一個(gè)元素的邊界之內(nèi)。對(duì) mouseover 事件而言更鲁,事件的主目標(biāo)是獲得光標(biāo)的元素霎箍,而相關(guān)元素(event.relatedTarget)就是那個(gè)失去光標(biāo)的元素。類似地澡为,對(duì) mouseout 事件而言漂坏,事件的主目標(biāo)是失去光標(biāo)的元素,而相關(guān)元素(event.relatedTarget)則是獲得光標(biāo)的元素媒至。來看下面的例子顶别。
<div id="myDivA" style="height:50px">in DIV A</div>
<div id="myDivB" style="height:50px">in DIV B</div>
<script>
function mouseOver(event){
event.target.style.fontSize = "50px";
event.relatedTarget.style.fontSize="5px";
}
myDivA = document.getElementById("myDivA");
myDivB = document.getElementById("myDivB");
myDivA.style.backgroundColor = "yellow";
myDivB.style.backgroundColor = "orange";
myDivA.addEventListener("mouseover", mouseOver, false);
myDivB.addEventListener("mouseover", mouseOver, false);
- 6. 鼠標(biāo)按鈕
- 只有在主鼠標(biāo)按鈕被單擊(或鍵盤回車鍵被按下)時(shí)才會(huì)觸發(fā) click 事件,因此檢測按鈕的信息并不是必要的塘慕。但對(duì)于 mousedown 和 mouseup 事件來說筋夏,則在其 event 對(duì)象存在一個(gè) button 屬性,表示按下或釋放的按鈕图呢。
- A number representing a given button:
0: Main button pressed, usually the left button or the un-initialized state
1: Auxiliary button pressed, usually the wheel button or the middle button (if present)
2: Secondary button pressed, usually the right button
3: Fourth button, typically the Browser Back button
4: Fifth button, typically the Browser Forward button
<button onmousedown="mouseClick(event)">click</button>
<script>
function mouseClick(event) {
alert(event.button); // event.button 當(dāng)鼠標(biāo)左鍵按下時(shí)条篷,值為0骗随,滾輪為1,右鍵為2赴叹;
}
7. 更多的事件信息
“DOM2 級(jí)事件”規(guī)范在 event 對(duì)象中還提供了 detail 屬性鸿染,用于給出有關(guān)事件的更多信息。對(duì)
于鼠標(biāo)事件來說乞巧, detail 中包含了一個(gè)數(shù)值涨椒,表示在給定位置上發(fā)生了多少次單擊。(最高只能計(jì)數(shù)到3)绽媒;altLeft:布爾值蚕冬,表示是否按下了 Alt 鍵。如果 altLeft 的值為 true是辕,則 altKey 的值也為 true囤热。
ctrlLeft:布爾值,表示是否按下了 Ctrl 鍵。如果 ctrlLeft 的值為 true,則 ctrlKey 的值
也為 true磕潮。shiftLeft:布爾值,表示是否按下了 Shift 鍵棺聊。如果 shiftLeft 的值為 true,則 shiftKey
的值也為 true贞谓。offsetX:光標(biāo)相對(duì)于目標(biāo)元素邊界的 x 坐標(biāo)限佩。
offsetY:光標(biāo)相對(duì)于目標(biāo)元素邊界的 y 坐標(biāo)。
8. 鼠標(biāo)滾輪事件
IE 6.0 首先實(shí)現(xiàn)了 mousewheel 事件裸弦。除了火狐其它都支持犀暑。當(dāng)用戶通過鼠標(biāo)滾輪與頁面交互、在垂直方向上滾動(dòng)頁面時(shí)(無論向上還是向下)烁兰,就會(huì)觸發(fā) mousewheel事件耐亏。當(dāng)用戶向上滾動(dòng)鼠標(biāo)滾輪時(shí),wheelDelta 是 120 的倍數(shù)沪斟;當(dāng)用戶向下滾動(dòng)鼠標(biāo)滾輪時(shí)广辰, wheelDelta 是-120 的倍數(shù)。
Firefox 支持一個(gè)名為 DOMMouseScroll 的類似事件主之,也是在鼠標(biāo)滾輪滾動(dòng)時(shí)觸發(fā)择吊。與 mousewheel事件一樣, DOMMouseScroll 也被視為鼠標(biāo)事件槽奕,因而包含與鼠標(biāo)事件有關(guān)的所有屬性几睛。而有關(guān)鼠標(biāo)滾輪的信息則保存在 detail 屬性中,當(dāng)向前滾動(dòng)鼠標(biāo)滾輪時(shí)粤攒,這個(gè)屬性的值是-3 的倍數(shù)所森,當(dāng)向后滾動(dòng)鼠標(biāo)滾輪時(shí)囱持,這個(gè)屬性的值是 3 的倍數(shù)。
- 13.4.4 鍵盤與文本事件
- 有 3 個(gè)鍵盤事件:
- keydown:當(dāng)用戶按下鍵盤上的任意鍵時(shí)觸發(fā)焕济,而且如果按住不放的話纷妆,會(huì)重復(fù)觸發(fā)此事件。
- keypress:當(dāng)用戶按下鍵盤上的字符鍵時(shí)觸發(fā)晴弃,而且如果按住不放的話掩幢,會(huì)重復(fù)觸發(fā)此事件。
按下 Esc 鍵也會(huì)觸發(fā)這個(gè)事件上鞠。Safari 3.1 之前的版本也會(huì)在用戶按下非字符鍵時(shí)觸發(fā) keypress
事件际邻。 - keyup:當(dāng)用戶釋放鍵盤上的鍵時(shí)觸發(fā)。
- 雖然所有元素都支持以上 3 個(gè)事件芍阎,但只有在用戶通過文本框輸入文本時(shí)才最常用到枯怖。
-
1. 鍵碼
- 在發(fā)生 keydown 和 keyup 事件時(shí), event 對(duì)象的 keyCode 屬性中會(huì)包含一個(gè)代碼能曾,與鍵盤上一個(gè)特定的鍵對(duì)應(yīng)。對(duì)數(shù)字字母字符鍵肿轨, keyCode 屬性的值與 ASCII 碼中對(duì)應(yīng)小寫字母或數(shù)字的編碼相同寿冕。
input = document.getElementById("myinput");
function keyPre(event){
li.innerHTML = event.key // event.key 返回字符本身
alert(event.keyCode); // event.keyCode 返回鍵碼,
}
- 使用 String.fromCharCode()將字符的ASCII碼轉(zhuǎn)換成實(shí)際的字符
<ul>
<li id="myLi"></li>
</ul>
<input type="text" id="myInput" onkeypress="keyEvent(event)">
<script>
li = document.getElementById("myLi");
function keyEvent(event) {
cc = event.charCode
li.innerHTML = cc + " " + String.fromCharCode(cc)
}
</script>
-
13.4.6 變動(dòng)事件
(DOM3 級(jí)事件模塊作廢了很多變動(dòng)事件, 建議改用MutationObserver構(gòu)造函數(shù)代替椒袍。)- DOM2 級(jí)的變動(dòng)(mutation)事件能在 DOM 中的某一部分發(fā)生變化時(shí)給出提示驼唱。
- DOMSubtreeModified:在 DOM 結(jié)構(gòu)中發(fā)生任何變化時(shí)觸發(fā)。這個(gè)事件在其他任何事件觸發(fā)后都會(huì)觸發(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ā)。這個(gè)事件在 DOMNodeRemoved 之后觸發(fā)帆焕。 - DOMAttrModified:在特性被修改之后觸發(fā)惭婿。
- DOMCharacterDataModified:在文本節(jié)點(diǎn)的值發(fā)生變化時(shí)觸發(fā)。
- 使用下列代碼可以檢測出瀏覽器是否支持變動(dòng)事件:
var isSupported = document.implementation.hasFeature("MutationEvents", "2.0");
-
1. 刪除節(jié)點(diǎn)
- 在使用removeChild()或replaceChild()從 DOM中刪除節(jié)點(diǎn)時(shí)叶雹,首先會(huì)觸發(fā)DOMNodeRemoved事件财饥。
- 如果被移除的節(jié)點(diǎn)包含子節(jié)點(diǎn),那么在其所有子節(jié)點(diǎn)以及這個(gè)被移除的節(jié)點(diǎn)上會(huì)相繼觸發(fā)DOMNodeRemovedFromDocument 事件折晦。但這個(gè)事件不會(huì)冒泡钥星,所以只有直接指定給其中一個(gè)子節(jié)點(diǎn)的事件處理程序才會(huì)被調(diào)用。
- 緊隨其后觸發(fā)的是 DOMSubtreeModified 事件满着。這個(gè)事件的目標(biāo)是被移除節(jié)點(diǎn)的父節(jié)點(diǎn)谦炒;
-
2. 插入節(jié)點(diǎn)
- 在使用 appendChild()贯莺、 replaceChild()或 insertBefore()向 DOM 中插入節(jié)點(diǎn)時(shí),首先會(huì)觸發(fā) DOMNodeInserted 事件编饺。
<button id="myBtn">delete</button>
<script>
btn = document.getElementById("myBtn");
btn.addEventListener("click", delElement);
function delElement(event){
img = document.createElement("img");
img.src = "box.jpg";
img.style.width = "100px";
img.style.height = "100px";
document.body.appendChild(img)
}
document.addEventListener("DOMNodeInserted", keyEvent)
function keyEvent(event) {
input.value = event.type + " " + event.target;
}
</script>
- 13.4.7 HTML5 事件
-
1. contextmenu 事件
- 用以表示何時(shí)應(yīng)該顯示上下文菜單乖篷,以便開發(fā)人員取消默認(rèn)的上下文菜單而提供自定義的菜單。上下文菜單是指在用戶交互(例如右鍵點(diǎn)擊)時(shí)出現(xiàn)的菜單透且。 HTML5允許我們自定義此菜單撕蔼。
<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>
<script>
function addContextMenu(event){
event.preventDefault(); //隱藏默認(rèn)上下文菜單;
menu = document.getElementById("myMenu");
menu.style.left = event.clientX + "px";
menu.style.top = event.clientY + "px";
menu.style.visibility = "visible";
}
div = document.getElementById("myDiv");
div.addEventListener("contextmenu", addContextMenu)
div.addEventListener("click", function (event) {
menu = document.getElementById("myMenu");
menu.style.visibility = "hidden";
})
</script>
- 所有瀏覽器都支持 contextmenu 事件秽誊, contextmenu元素只有 Firefox 瀏覽器支持鲸沮。
<div contextmenu="mymenu">右擊這里顯示上下文菜單。
<menu type="context" id="mymenu">
<menuitem label="Refresh"></menuitem>
<menuitem label="Twitter"></menuitem>
</menu>
</div>
- 在所有瀏覽器中都可以取消這個(gè)事件:在兼容 DOM 的瀏覽器中锅论,使用 event.preventDefalut()讼溺;在 IE 中,將 event.returnValue 的值設(shè)置為 false最易。
-
2. beforeunload 事件
- 可以監(jiān)聽到瀏覽器關(guān)閉操作怒坯,能夠在關(guān)閉之前,彈出一個(gè)對(duì)話框藻懒,讓用戶選擇是否關(guān)閉剔猿。(只有IE支持?)
- 為了顯示這個(gè)彈出對(duì)話框嬉荆,必須將 event.returnValue 的值設(shè)置為要顯示給用戶的字符串(對(duì)
IE 及 Fiefox 而言)归敬,同時(shí)作為函數(shù)的值返回(對(duì) Safari 和 Chrome 而言)(?鄙早?汪茧?Chrome和火狐不支持);
function myFunc(event){
var message = "I'm really going to miss you if you go.";
event.returnValue = message;
}
window.addEventListener("beforeunload", myFunc)
-
3. DOMContentLoaded 事件
- 在形成完整的 DOM 樹之后就會(huì)觸發(fā)限番,不理會(huì)圖像舱污、 JavaScript 文件、 CSS 文件或其他資源是否已經(jīng)下載完畢弥虐。而 load 事件是在頁面中的一切都加載完畢時(shí)觸發(fā)慌闭。
- 可以為 document 或 window 添加 DOMContentLoaded 事件(盡管
這個(gè)事件會(huì)冒泡到 window,但它的目標(biāo)實(shí)際上是 document)躯舔。 - 這個(gè)事件始終都會(huì)在 load 事件之前觸發(fā)驴剔。
-
4. readystatechange 事件
- 提供與文檔或元素的加載狀態(tài)有關(guān)的信息。
- 當(dāng)對(duì)象的readyState屬性值發(fā)生變化時(shí)出發(fā)此事件粥庄。
- readyState屬性值有:
- loading:加載(document 仍在加載丧失。)
- interactive / 互動(dòng)(文檔已經(jīng)完成加載,文檔已被解析惜互,但是諸如圖像布讹,樣式表和框架之類的子資源仍在加載琳拭。)
- complete / 完成(T文檔和所有子資源已完成加載。狀態(tài)表示 load 事件即將被觸發(fā)描验。 )
document.addEventListener("readystatechange", function(event){
alert("load completed")
})
- 對(duì)于 document 而言白嘁,值為"interactive"的 readyState 會(huì)在與 DOMContentLoaded 大致相同的時(shí)刻觸發(fā) readystatechange 事件。
// 以下類似使用DOMContentLoaded
document.addEventListener("readystatechange", function(event){
if (document.readyState == "interactive"){
alert("Content loaded");
}
})
- 交互階段可能會(huì)早于也可能會(huì)晚于完成階段出現(xiàn)膘流,無法確保順序絮缅。在包含
較多外部資源的頁面中,交互階段更有可能早于完成階段出現(xiàn)呼股;而在頁面中包含較少外部資源的情況下耕魄,完成階段先于交互階段出現(xiàn)的可能性更大。因此彭谁,為了盡可能搶到先機(jī)吸奴,有必要同時(shí)檢測交互和完成階段。
document.addEventListener("readystatechange", function(event){
if (document.readyState == "interactive" || document.readyState == "complete"){
document.removeEventListener("readystatechange", arguments.callee);
alert("Content loaded");
}
})
另外缠局, <script>(在 IE 和 Opera 中)和<link>(僅 IE 中)元素也會(huì)觸發(fā) readystatechange事件则奥,可以用來確定外部的 JavaScript 和 CSS 文件是否已經(jīng)加載完成。
-
5. pageshow 和 pagehide 事件
- Firefox 和 Opera 有一個(gè)特性狭园,名叫“往返緩存”(back-forward cache读处,或 bfcache),可以在用戶使用瀏覽器的“后退”和“前進(jìn)”按鈕時(shí)加快頁面的轉(zhuǎn)換速度妙啃。將整個(gè)頁面都保存在了內(nèi)存里。如果頁面位于 bfcache 中俊戳, 再次打開該頁面時(shí)就不會(huì)觸發(fā) load 事件揖赴。但為了更形象地說明 bfcache 的行為, Firefox 還是提供了一些新事件:
- pageshow:這個(gè)事件在頁面顯示時(shí)觸發(fā)抑胎,無論該頁面是否來自 bfcache燥滑。
- 在重新加載的頁面中, pageshow 會(huì)在 load 事件觸發(fā)后觸發(fā)阿逃;而對(duì)于 bfcache 中的頁面铭拧, pageshow 會(huì)在頁面狀態(tài)完全恢復(fù)的那一刻觸發(fā)。另外要注意的是恃锉,雖然這個(gè)事件的目標(biāo)是 document搀菩,但必須將其事件處理程序添加到 window。
// 這個(gè)例子使用了私有作用域破托,以防止變量 showCount 進(jìn)入全局作用域肪跋。
(function(event){
var showCount = 0;
window.addEventListener("load", function(){
alert("Load fired");
});
// 離開之后,又單擊“后退”按鈕返回該頁面土砂,就會(huì)看到 showCount每次遞增的值州既。
window.addEventListener("pageshow", function(event){
showCount++;
alert("Show has been fired " + showCount + " times.");
alert("Show has been fired " + showCount + " times. Persisted? " + event.persisted); // event有個(gè)persisted谜洽, 如果頁面被保存在了 bfcache 中,則這個(gè)屬性的值為 true吴叶;
});
})();
- pagehide 事件(阐虚??蚌卤?实束??造寝?):該事件會(huì)在瀏覽器卸載頁面的時(shí)候觸發(fā)磕洪,而且是在unload 事件之前觸發(fā)。
- 這個(gè)事件的 event 對(duì)象也包含 persisted 屬性诫龙,不過其用途稍有不同析显;如果頁面在卸載之后會(huì)被保存在 bfcache 中,那么 persisted 的值也會(huì)被設(shè)置為 true签赃。因此谷异,當(dāng)?shù)谝淮斡|發(fā) pageshow 時(shí), persisted 的值一定是 false锦聊,而在第一次觸發(fā) pagehide 時(shí)歹嘹, persisted 就會(huì)變成 true(除非頁面不會(huì)被保存在 bfcache 中)
(function(){
window.addEventListener("pagehide", function(event){
alert("Hiding. Persisted? " + event.persisted);
});
})();
- **6. hashchange 事件 **???????
- 在 URL 的參數(shù)列表(及 URL 中“ #”號(hào)后面的所有字符串)
發(fā)生變化時(shí)觸發(fā);
- 在 URL 的參數(shù)列表(及 URL 中“ #”號(hào)后面的所有字符串)
window.addEventListener("hashchange", function(event){
alert("Old URL: " + event.oldURL + "\nNew URL: " + event.newURL);
});
13.5 內(nèi)存和性能
-
13.5.1 事件委托
- 對(duì)“事件處理程序過多”問題的解決方案就是事件委托。事件委托利用了事件冒泡孔庭,只指定一個(gè)事件處理程序尺上,就可以管理某一類型的所有事件。
<ul id="myLinks">
<li id="goSomewhere">Go somewhere</li>
<li id="doSomething">Do something</li>
<li id="sayHi">Say hi</li>
</ul>
<script>
var list = document.getElementById("myLinks");
list.addEventListener("click", function(event){
switch(event.target.id){
case "doSomething":
document.title = "I changed the document's title";
break;
case "goSomewhere":
location.;
break;
case "sayHi":
alert("hi");
break;
}
});
</script>
-
如果可行的話圆到,也可以考慮為 document 對(duì)象添加一個(gè)事件處理程序怎抛,用以處理頁面上發(fā)生的某種特定類型的事件。
- document 對(duì)象很快就可以訪問芽淡,而且可以在頁面生命周期的任何時(shí)點(diǎn)上為它添加事件處理程序(無需等待 DOMContentLoaded 或 load 事件)马绝。換句話說,只要可單擊的元素呈現(xiàn)在頁面上挣菲,就可以立即具備適當(dāng)?shù)墓δ堋?/li>
- 在頁面中設(shè)置事件處理程序所需的時(shí)間更少富稻。只添加一個(gè)事件處理程序所需的 DOM 引用更少,
所花的時(shí)間也更少白胀。 - 整個(gè)頁面占用的內(nèi)存空間更少椭赋,能夠提升整體性能。
最適合采用事件委托技術(shù)的事件包括 click或杠、mousedown纹份、mouseup、keydown、keyup 和 keypress蔓涧。
-
13.5.2 移除事件處理程序
- 使用 innerHTML 替換頁面中某一部分的時(shí)候件已, 或使用 removeChild()和 replaceChild()方法時(shí),內(nèi)存中會(huì)留下那些過時(shí)不用的“空事件處理程序”(dangling event handler)元暴,也是造成 Web 應(yīng)用程序內(nèi)存與性能問題的主要原因篷扩。
- 如果你知道某個(gè)元素即將被移除,那么最好手工移除事件處理程序茉盏,如下面的例子所示鉴未。
<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>
導(dǎo)致“空事件處理程序”的另一種情況,就是卸載頁面的時(shí)候鸠姨。在頁面卸載之前铜秆,先通過 onunload 事件處理程序移除所有事件處理程序。
13.6 模擬事件
13.6.1 DOM中的事件模擬
-
創(chuàng)建和分派DOM事件讶迁。這些事件通常稱為合成事件连茧,而不是瀏覽器本身觸發(fā)的事件。
- 創(chuàng)建自定義事件: Events 可以使用構(gòu)造函數(shù)創(chuàng)建巍糯;
//創(chuàng)建自定義事件
var event = new Event('click');
// 添加事件監(jiān)聽
elem.addEventListener('click', function (event) { do something.. }, false);
// 派發(fā)事件
elem.dispatchEvent(event);
- 添加自定義數(shù)據(jù) – CustomEvent()
- 使用CustomEvent接口的事件可用于攜帶自定義數(shù)據(jù)啸驯。
- IE瀏覽器不支持此方法,需要用 var event = document.createEvent('CustomEvent');
<script type="text/javascript">
function onClick(event){alert(event.detail)} // 調(diào)用函數(shù)
div = document.getElementById("myDiv");
nowDate = new Date(); // 時(shí)間實(shí)例
// 創(chuàng)建CustomEvent Dict的可用event按鍵取值祟峦,可放任何數(shù)據(jù)罚斗;
// 還有更多可選參數(shù) 可在MDN里查看
var myCustomEvent = new CustomEvent('click', {'detail': nowDate.toLocaleDateString()});
div.addEventListener("click", onClick, false); // 添加監(jiān)聽;
div.dispatchEvent(myCustomEvent) // 向元素派發(fā)事件
</script>
2018/11/7