事件委托與事件對象 事件冒泡與事件捕獲 事件流:用於描述頁面接收事件的順序。以下是事件流的兩種不同方案: 事件冒泡:事件由最具體的元素逐級向上傳遞到最不具體的元素。 事件捕獲:事件由最不具體的元素逐級向下傳遞到最具體的元素。 以上的兩種事件流方案是截然相反的,分別由IE開發團隊和Netscape開發 ...
目錄
事件委托與事件對象
事件冒泡與事件捕獲
事件流:用於描述頁面接收事件的順序。以下是事件流的兩種不同方案:
事件冒泡:事件由最具體的元素逐級向上傳遞到最不具體的元素。
事件捕獲:事件由最不具體的元素逐級向下傳遞到最具體的元素。
以上的兩種事件流方案是截然相反的,分別由IE開發團隊和Netscape開發團隊提出。
添加事件處理的方法
HTML事件處理程式:利用特定HTML標簽的事件屬性(<input>
)。代碼如下:
<input type="button" value="測試" onclick="test()">
<script>
let test = () => { // 利用標簽屬性添加事件
console.log('已被點擊')
}
</script>
DOM0事件處理程式:利用DOM節點自帶的事件屬性。代碼如下:
<input type="button" value="測試" id="test">
<script>
let test = document.querySelector('#test')
test.onclick = () => { // 利用onlick屬性添加事件
console.log('已被點擊')
}
</script>
DOM2事件處理程式(推薦):利用DOM節點(繼承自EventTarget)的添加事件監聽器方法。代碼如下:
<input type="button" value="測試" id="test">
<script>
let test = document.querySelector('#test')
test.addEventListener('click', ()=>{ // 利用添加事件監聽器方法
console.log('已被點擊')
})
</script>
說明:在網頁DOM編程中的繼承關係:EventTarget
<= Node
<= Element
。因此上面的test
變數擁有addEventListener
方法
DOM2 Events事件流

捕獲階段:Document
=> Element html
=> Element body
=> Element div
冒泡階段:Element div
=> Element body
=> Element html
=> Document
我們首先瞭解EventTarget.addEventListener(type, listener, options)
這個方法的一些內部參數:
type
:監聽事件的類型
listener
:接收一個回調函數,事件觸發後會執行。
options
:裡面有比較多的可選項參數,這裡我們利用capture
(布爾值:預設為false)這個參數。表示監聽的事件在捕獲階段會觸發listener
執行。
接下來我們利用上面的方法還原上面DOM2事件流的捕獲階段與冒泡階段,如下:
<div style="cursor: pointer">我是一個事件,請點擊驗證</div>
<script>
// 捕獲階段
document.addEventListener("click", () => {
console.log("捕獲階段1:Document") // document
}, true)
document.documentElement.addEventListener("click", () => {
console.log("捕獲階段2:Element html") // html
}, true)
document.body.addEventListener("click", () => {
console.log("捕獲階段3:Element body") // body
}, true)
document.querySelector("div").addEventListener("click", () => {
console.log("捕獲階段4:Element div") // div
}, true)
// 冒泡階段
document.querySelector("div").addEventListener("click", () => {
console.log("冒泡階段4:Element div") // div
}, false)
document.body.addEventListener("click", () => {
console.log("冒泡階段5:Element body") // body
}, false)
document.documentElement.addEventListener("click", () => {
console.log("冒泡階段6:Element html") // html
}, false)
document.addEventListener("click", () => {
console.log("冒泡階段7:Document") // document
}, false)
</script>

很明顯,上面的代碼驗證了網頁的事件觸發會存在DOM2事件流這一執行過程。我們點擊了事件,這個事件經歷了由捕獲階段再到冒泡階段的傳遞。
事件對象常用屬性和方法
方法屬性 | 說明 |
---|---|
Event.target 只讀 |
對事件原始目標的引用。 |
Event.type 只讀 |
事件的類型,不區分大小寫。 |
event.preventDefault |
取消預設事件(如果該事件可取消)。 |
event.stopPropagation |
停止冒泡,阻止事件在 DOM 中繼續冒泡。 |
其中Event.target
最為常用,具體指代觸發了相應事件的Node
節點目標。
事件委托的應用(實現hover
懸停變色效果)
需求:實現一個列表,滑鼠進入或離開都會使列表子元素的背景顏色改變。
如果沒有事件委托,我們一般實現這個需求應該這樣做。如下:
<div class="list" style="height: 400px; width: 400px;">
<ul style="list-style: none; text-align: center;">
<li>1</li>
<li>2</li>
<li>3</li>
<li>4</li>
</ul>
</div>
<script>
let list = document.querySelectorAll('.list > ul > li');
// 遍歷DOM集合,給每個li添加事件
list.forEach(element => {
element.addEventListener('mouseover', () => {
element.style.backgroundColor = 'green';
})
element.addEventListener('mouseout', () => {
element.style.backgroundColor = '';
})
});
</script>
我們遍歷每個li
元素併為其添加滑鼠移入與移出事件。目前總共添加了八個事件處理程式。
註意:在JavaScript中,事件處理程式的數量會影響頁面的整體性能。
因此對上述實現方式我們有必要採取措施優化。利用事件委托優化如下:
// 點擊li元素後會通過事件冒泡機制觸發ul添加的click事件。
<div class="list" style="height: 400px; width: 400px;">
<ul style="list-style: none; text-align: center;">
<li>1</li>
<li>2</li>
<li>3</li>
<li>4</li>
</ul>
</div>
<script>
let list = document.querySelector('.list > ul');
// 直接給ul父元素添加事件即可
list.addEventListener('mouseover', (event) => {
if (event.target.nodeName.toLowerCase() === 'li') {
event.target.style.backgroundColor = 'green';
}
})
list.addEventListener('mouseout', (event) => {
if (event.target.nodeName.toLowerCase() === 'li') {
event.target.style.backgroundColor = '';
}
})
</script>
我們只給list
元素添加了兩個事件,同樣實現了需求。如果採用原始方式,我們一共給這些li
元素添加了八個事件。利用事件委托的方式進行網頁性能的優化,其效果不言而喻。
參考