從頭說起
如果需要給html中的某個dom綁定事件,有三種常用方法:
1.直接寫在dom的事件鉤子上
<span id="target" onClick="handleClick()">Click me</span>
這種方法破壞了dom和js分離的規(guī)則,所以不太被推薦,如果面試官讓你做題,盡量別這么寫,他們會單純地以為你很low
2.通過js代碼注冊事件
var target = document.getElementById('target');
target.onclick = function() {
// do something...
}
這種方式會比第一種方式更有“儀式感”,但是缺點(diǎn)也顯而易見,只能綁定一次事件,下次綁定會清空上次綁定的事件
3.通過addEventListener來注冊事件
var target = document.getElementById('target');
target.addEventListener('click', function() {
// do something...
}, false); // 如果不加第三個參數(shù),默認(rèn)是false
這種方式最為靈活,也是被普遍建議采用的事件綁定方式,那么問題來了,這第三個參數(shù)是用來干嘛的?
由于瀏覽器有事件冒泡的機(jī)制存在,當(dāng)你點(diǎn)擊一個dom,點(diǎn)擊事件會沿著dom樹結(jié)構(gòu)像上或者下進(jìn)行傳播,如果你不想被其他相關(guān)節(jié)點(diǎn)相應(yīng)到此次點(diǎn)擊事件,那么就需要傳說中的“阻止事件冒泡”了
假設(shè)div、p、span元素都有click事件的響應(yīng)邏輯,
- 當(dāng)?shù)谌齻€參數(shù)為
false時(不傳參數(shù)時,默認(rèn)也是這種冒泡方式),點(diǎn)擊<span />后,接下來<p />會響應(yīng)此次事件,然后是<div />,既事件從上往下冒泡,如下圖

propagation-false.png
當(dāng)?shù)谌齻€參數(shù)為true時,點(diǎn)擊<span />后,首先響應(yīng)事件的是最底層的<div />,隨后是<p />,最后才是你點(diǎn)擊的<span />,如下圖

propagation-true.png
__
其他小貼士
- 如何分辨事件是由冒泡產(chǎn)生的還是操作產(chǎn)生的?
在事件處理函數(shù)中,可以通過
function handleClick (evt) {
if (evt.phase === 1) {
// 第三個參數(shù)為true時所導(dǎo)致的冒泡
} else if (evt.phase === 3) {
// 第三個參數(shù)為false時所導(dǎo)致的冒泡
} else if (evt.phase === 2) {
// 發(fā)生在當(dāng)前dom的事件
}
}
- 如何阻止事件冒泡?
在事件處理函數(shù)中,可以通過
function handleClick(evt) {
evt.stopPropagation();
// 或者
evt.stopImmediatePropagation();
}
上面的阻止冒泡不會阻止本dom本事件的其他事件處理函數(shù)的執(zhí)行;
下面的阻止冒泡會導(dǎo)致后續(xù)綁定在該dom的其他事件處理函數(shù)不再執(zhí)行;