事件的本質(zhì)是程序各個組成部分之間的一種通信方式,也是異步編程的一種實現(xiàn)。DOM 支持大量的事件,本章開始介紹 DOM 的事件編程。
介紹具體的事件之前,先來看看如何讓 DOM 節(jié)點監(jiān)聽事件。
概述
DOM 節(jié)點的事件操作(監(jiān)聽和觸發(fā)),都定義在EventTarget
接口。所有節(jié)點對象都部署了這個接口,其他一些需要事件通信的瀏覽器內(nèi)置對象(比如,XMLHttpRequest
、AudioNode
、AudioContext
)也部署了這個接口。
該接口主要提供三個實例方法。
addEventListener()
:綁定事件的監(jiān)聽函數(shù)removeEventListener()
:移除事件的監(jiān)聽函數(shù)dispatchEvent()
:觸發(fā)事件
EventTarget.addEventListener()
EventTarget.addEventListener()
用于在當前節(jié)點或?qū)ο笊希床渴鹆?EventTarget 接口的對象),定義一個特定事件的監(jiān)聽函數(shù)。一旦這個事件發(fā)生,就會執(zhí)行監(jiān)聽函數(shù)。該方法沒有返回值。
target.addEventListener(type, listener[, useCapture]);
該方法接受三個參數(shù)。
type
:事件名稱,大小寫敏感。listener
:監(jiān)聽函數(shù)。事件發(fā)生時,會調(diào)用該監(jiān)聽函數(shù)。useCapture
:布爾值,如果設(shè)為true
,表示監(jiān)聽函數(shù)將在捕獲階段(capture)觸發(fā)(參見后文《事件的傳播》部分)。該參數(shù)可選,默認值為false
(監(jiān)聽函數(shù)只在冒泡階段被觸發(fā))。
下面是一個例子。
function hello() {
console.log('Hello world');
}
var button = document.getElementById('btn');
button.addEventListener('click', hello, false);
上面代碼中,button
節(jié)點的addEventListener()
方法綁定click
事件的監(jiān)聽函數(shù)hello()
,該函數(shù)只在冒泡階段觸發(fā)。
關(guān)于參數(shù),有兩個地方需要注意。
首先,第二個參數(shù)除了監(jiān)聽函數(shù),還可以是一個具有handleEvent
方法的對象,效果與監(jiān)聽函數(shù)一樣。
buttonElement.addEventListener('click', {
handleEvent: function (event) {
console.log('click');
}
});
上面代碼中,addEventListener()
方法的第二個參數(shù),就是一個具有handleEvent()
方法的對象。
其次,第三個參數(shù)除了布爾值useCapture
,還可以是一個監(jiān)聽器配置對象,定制事件監(jiān)聽行為。該對象有以下屬性。
capture
:布爾值,如果設(shè)為true
,表示監(jiān)聽函數(shù)在捕獲階段觸發(fā),默認為false
,在冒泡階段觸發(fā)。once
:布爾值,如果設(shè)為true
,表示監(jiān)聽函數(shù)執(zhí)行一次就會自動移除,后面將不再監(jiān)聽該事件。該屬性默認值為false
。passive
:布爾值,設(shè)為true
時,表示禁止監(jiān)聽函數(shù)調(diào)用preventDefault()
方法。如果調(diào)用了,瀏覽器將忽略這個要求,并在控制臺輸出一條警告。該屬性默認值為false
。signal
:該屬性的值為一個 AbortSignal 對象,為監(jiān)聽器設(shè)置了一個信號通道,用來在需要時發(fā)出信號,移除監(jiān)聽函數(shù)。
下面是once
屬性的例子,讓監(jiān)聽函數(shù)只執(zhí)行一次。
element.addEventListener('click', function (event) {
// 只執(zhí)行一次的代碼
}, {once: true});
addEventListener()
方法可以為針對當前對象的同一個事件,添加多個不同的監(jiān)聽函數(shù)。這些函數(shù)按照添加順序觸發(fā),即先添加先觸發(fā)。如果為同一個事件多次添加同一個監(jiān)聽函數(shù),該函數(shù)只會執(zhí)行一次,多余的添加將自動被去除(不必使用removeEventListener()
方法手動去除)。
function hello() {
console.log('Hello world');
}
document.addEventListener('click', hello, false);
document.addEventListener('click', hello, false);
執(zhí)行上面代碼,點擊文檔只會輸出一行Hello world
。
如果希望向監(jiān)聽函數(shù)傳遞參數(shù),可以用匿名函數(shù)包裝一下監(jiān)聽函數(shù)。
function print(x) {
console.log(x);
}
var el = document.getElementById('div1');
el.addEventListener('click', function () { print('Hello'); }, false);
上面代碼通過匿名函數(shù),向監(jiān)聽函數(shù)print
傳遞了一個參數(shù)。
監(jiān)聽函數(shù)內(nèi)部的this
,指向當前事件所在的那個對象。
// HTML 代碼如下
// <p id="para">Hello</p>
var para = document.getElementById('para');
para.addEventListener('click', function (e) {
console.log(this.nodeName); // "P"
}, false);
上面代碼中,監(jiān)聽函數(shù)內(nèi)部的this
指向事件所在的對象para
。
EventTarget.removeEventListener()
EventTarget.removeEventListener()
方法用來移除addEventListener()
方法添加的事件監(jiān)聽函數(shù)。該方法沒有返回值。
div.addEventListener('click', listener, false);
div.removeEventListener('click', listener, false);
removeEventListener()
方法的參數(shù),與addEventListener()
方法完全一致。它的第一個參數(shù)“事件類型”,大小寫敏感。
注意,removeEventListener()
方法移除的監(jiān)聽函數(shù),必須是addEventListener()
方法添加的那個監(jiān)聽函數(shù),而且必須在同一個元素節(jié)點,否則無效。
div.addEventListener('click', function (e) {}, false);
div.removeEventListener('click', function (e) {}, false);
上面代碼中,removeEventListener()
方法無效,因為監(jiān)聽函數(shù)不是同一個匿名函數(shù)。
element.addEventListener('mousedown', handleMouseDown, true);
element.removeEventListener("mousedown", handleMouseDown, false);
上面代碼中,removeEventListener()
方法也是無效的,因為第三個參數(shù)不一樣。
EventTarget.dispatchEvent()
EventTarget.dispatchEvent()
方法在當前節(jié)點上觸發(fā)指定事件,從而觸發(fā)監(jiān)聽函數(shù)的執(zhí)行。該方法返回一個布爾值,只要有一個監(jiān)聽函數(shù)調(diào)用了Event.preventDefault()
,則返回值為false
,否則為true
。
target.dispatchEvent(event)
dispatchEvent()
方法的參數(shù)是一個Event
對象的實例(詳見《Event 對象》章節(jié))。
para.addEventListener('click', hello, false);
var event = new Event('click');
para.dispatchEvent(event);
上面代碼在當前節(jié)點觸發(fā)了click
事件。
如果dispatchEvent()
方法的參數(shù)為空,或者不是一個有效的事件對象,將報錯。
下面代碼根據(jù)dispatchEvent()
方法的返回值,判斷事件是否被取消了。
var canceled = !cb.dispatchEvent(event);
if (canceled) {
console.log('事件取消');
} else {
console.log('事件未取消');
}
更多建議: