想象一個餐廳的點餐系統(tǒng)
可以把 JavaScript 的事件模型想象成一個餐廳的運作方式:
- 顧客(事件):就像各種事件(點擊、滾動、鍵盤輸入等)
- 服務(wù)員(事件監(jiān)聽器):負(fù)責(zé)接收并處理顧客的請求
- 點餐單(事件隊列):所有顧客的請求都按順序排在這里等待處理
- 廚師(JavaScript 引擎):一次只能做一個菜(單線程),按順序處理點餐單
事件模型的三個階段
1. 捕獲階段(從上往下)
就像餐廳經(jīng)理先聽到顧客喊服務(wù)員(從窗戶到餐桌):
事件從最外層(window)向內(nèi)傳遞到目標(biāo)元素
很少使用,就像經(jīng)理一般不直接處理點餐
2. 目標(biāo)階段
服務(wù)員到達(dá)餐桌:
事件到達(dá)實際被點擊的元素
這是我們最常處理的階段
3. 目標(biāo)階段
冒泡階段(從下往上)
服務(wù)員把訂單報給廚師:
事件從目標(biāo)元素向外傳遞到最外層
默認(rèn)情況下事件監(jiān)聽器在這個階段觸發(fā)
// 就像三個不同級別的員工
document.querySelector('.爺爺').addEventListener('click', () => {
console.log('經(jīng)理知道了'); // 捕獲階段
}, true); // true 表示在捕獲階段監(jiān)聽
document.querySelector('.爸爸').addEventListener('click', () => {
console.log('領(lǐng)班處理中'); // 冒泡階段(默認(rèn))
});
document.querySelector('.兒子').addEventListener('click', () => {
console.log('服務(wù)員接待'); // 目標(biāo)階段
});
事件委托:聰明的經(jīng)理
利用冒泡機制,把事件處理交給上級元素:
// 不用給每個按鈕都安排服務(wù)員
document.querySelector('.按鈕容器').addEventListener('click', (event) => {
if(event.target.classList.contains('按鈕')) {
console.log('你點擊了:', event.target.textContent);
}
});
優(yōu)點:
節(jié)省內(nèi)存(減少事件監(jiān)聽器)
動態(tài)元素也能響應(yīng)(新加的按鈕自動有效)
常見事件類型
鼠標(biāo)事件:click(點擊)、mouseover(懸停)
鍵盤事件:keydown(按鍵按下)、keyup(按鍵松開)
表單事件:submit(提交)、change(內(nèi)容改變)
頁面事件:load(加載完成)、scroll(滾動)
實際應(yīng)用技巧
阻止冒泡:event.stopPropagation()(不讓經(jīng)理知道)
阻止默認(rèn)行為:event.preventDefault()(不讓鏈接跳轉(zhuǎn))
一次性事件:{ once: true }(只處理第一次點擊)
document.querySelector('a').addEventListener('click', (event) => {
event.preventDefault(); // 阻止鏈接跳轉(zhuǎn)
console.log('點擊了但不會跳轉(zhuǎn)');
});
document.querySelector('button').addEventListener('click', (event) => {
event.stopPropagation(); // 阻止事件冒泡
console.log('只有我會響應(yīng)');
}, { once: true }); // 只生效一次