什么是 DOM 事件
- DOM 事件是瀏覽器的一個(gè)功能,是瀏覽器或者用戶針對(duì)頁面做出的某些動(dòng)作匣椰,比如點(diǎn)擊板惑,鼠標(biāo)移動(dòng)橄镜,鍵盤輸入等。
- DOM 事件是用戶與頁面進(jìn)行交互的核心冯乘,當(dāng)事件觸發(fā)時(shí)洽胶,可以綁定一個(gè)或多個(gè)事件處理函數(shù),來完成我們要實(shí)現(xiàn)的功能裆馒。
DOM 事件模型
DOM 事件模型分類兩種姊氓,事件冒泡和事件捕獲。當(dāng)某一事件觸發(fā)時(shí)喷好,先執(zhí)行捕獲再執(zhí)行冒泡翔横。
事件冒泡
當(dāng)子元素的事件類型觸發(fā)時(shí),所有父元素上綁定同類型事件均會(huì)從內(nèi)到外層層觸發(fā)梗搅。
代碼示例
<body>
<div class="grandparent">
祖父元素
<div class="parent">
父元素
<div class="children">子元素</div>
</div>
</div>
<script>
let children = document.querySelector('.children')
let parent = document.querySelector('.parent')
let grandparent = document.querySelector('.grandparent')
// 這里的綁定的三個(gè)事件類型相同禾唁,均為 click,如果不相同則不會(huì)執(zhí)行事件冒泡
children.addEventListener('click', () => {
console.log ('子元素被點(diǎn)擊了')
})
parent.addEventListener('click', () => {
console.log ('父元素被點(diǎn)擊了')
})
grandparent.addEventListener('click', () => {
console.log ('祖父元素被點(diǎn)擊了')
})
</script>
</body>
當(dāng)點(diǎn)擊子元素時(shí)无切,控制臺(tái)打印如下結(jié)果
事件捕獲
當(dāng)子元素的事件類型觸發(fā)時(shí)荡短,所有父元素上綁定的同類型事件均會(huì)從外到內(nèi)層層觸發(fā)。
代碼示例
<body>
<div class="grandparent">
祖父元素
<div class="parent">
父元素
<div class="children">子元素</div>
</div>
</div>
<script>
let children = document.querySelector('.children')
let parent = document.querySelector('.parent')
let grandparent = document.querySelector('.grandparent')
children.addEventListener('click', () => {
console.log ('子元素被點(diǎn)擊了')
}, true)
parent.addEventListener('click', () => {
console.log ('父元素被點(diǎn)擊了')
}, true)
grandparent.addEventListener('click', () => {
console.log ('祖父元素被點(diǎn)擊了')
}, true)
</script>
</body>
當(dāng)點(diǎn)擊子元素時(shí)哆键,控制臺(tái)打印如下結(jié)果
事件對(duì)象
每當(dāng)事件觸發(fā)時(shí)掘托,瀏覽器會(huì)把當(dāng)前事件觸發(fā)的詳情信息記錄下來,并把它們封裝成一個(gè)對(duì)象籍嘹,可以傳遞給事件處理函數(shù)闪盔。
children.addEventListener('click', (e) => {
console.log ('子元素被點(diǎn)擊了')
console.log(e)
}, true) // e 為事件對(duì)象
e.target 和 e.currentTarget 的區(qū)別
e.target
用戶操作的元素
e.currentTarget
程序員監(jiān)聽的元素
代碼示例
children.addEventListener('click', (e) => {
console.log('子元素被點(diǎn)擊了')
console.log(e.target) // 輸出子元素
console.log(e.currentTarget); // 輸出子元素
})
parent.addEventListener('click', (e) => {
console.log('父元素被點(diǎn)擊了')
console.log(e.target) // 輸出子元素或父元素
console.log(e.currentTarget) // 輸出父元素
})
console.log(e) // 報(bào)錯(cuò) Uncaught ReferenceError: e is not defined
當(dāng)點(diǎn)擊子元素時(shí),控制臺(tái)打印出如下結(jié)果
兩個(gè)點(diǎn)擊事件的 e.target
值都是用戶點(diǎn)擊子元素噩峦,而 e.currentTarget
則是事件觸發(fā)的元素锭沟,用戶點(diǎn)擊觸發(fā)的元素 e.target
和 e.currentTarget
的值是相同的,通過事件冒泡和事件捕獲觸發(fā)的元素识补,e.target
和 e.currentTarget
的值是不相同的族淮。
當(dāng)事件結(jié)束后,事件對(duì)象 e 就不存在凭涂。
阻止事件冒泡和事件捕獲
通過 e.stopPropagation()
可以阻止事件冒泡和事件捕獲
阻止事件冒泡
代碼示例
children.addEventListener('click', (e) => {
console.log('子元素被點(diǎn)擊了')
})
parent.addEventListener('click', (e) => {
console.log('父元素被點(diǎn)擊了')
e.stopPropagation() // 當(dāng)代碼執(zhí)行到這里時(shí)祝辣,停止事件傳播
})
grandparent.addEventListener('click', (e) => {
console.log('祖父元素被點(diǎn)擊了') // 這里不會(huì)打印出來
})
阻止事件捕獲
- 子元素不能阻止父元素的事件捕獲
代碼示例
children.addEventListener('click', (e) => {
console.log('子元素被點(diǎn)擊了') // 這里不會(huì)打印出來
})
parent.addEventListener('click', (e) => {
console.log('父元素被點(diǎn)擊了')
e.stopPropagation() // 當(dāng)代碼執(zhí)行到這里時(shí),停止事件傳播
})
grandparent.addEventListener('click', (e) => {
console.log('祖父元素被點(diǎn)擊了')
})
取消默認(rèn)事件
e.preventDefault() // w3c 的寫法
e.returnValue = false // IE 的寫法
- 元素有默認(rèn)事件才可以取消切油,如果元素本身沒有默認(rèn)事件或者元素不支持取消默認(rèn)事件(如滾動(dòng)條)蝙斜,則調(diào)用無效。
- 不可取消冒泡和不可取消默認(rèn)事件的元素可以通過 MDN 英文版搜索 元素 event 澎胡,看到 Bubbles (冒泡) 和(Cancelable)是否支持孕荠。
什么元素有默認(rèn)事件
<a> 鏈接
<inpunt type='submit'> 表單提交按鈕
οncοntextmenu 右鍵菜單
onmousewheel 鼠標(biāo)滾輪
touchstart 觸屏滑動(dòng)
代碼示例
<body>
<a >百度</a>
<script>
a.onclick = (e) => {
if (e.preventDefault) {
e.preventDefault()
console.log('鏈接跳轉(zhuǎn)被阻止了')
} else {
window.event.returnValue = false
console.log('鏈接跳轉(zhuǎn)被阻止了')
}
}
</script>
</body>