下面HTML代碼
<div class="grandfather">
<div class="father">
<div class="son">
點(diǎn)擊
</div>
</div>
</div>//另設(shè)置有監(jiān)聽函數(shù)
點(diǎn)擊的時(shí)候點(diǎn)擊了誰?
兒子汽久,爸爸男杈,爺爺都點(diǎn)擊了
調(diào)用順序是什么栏妖?
W3C發(fā)布標(biāo)準(zhǔn):
首先按照爺爺=>爸爸=>兒子的順序看有沒有監(jiān)聽函數(shù)(網(wǎng)景標(biāo)準(zhǔn))稱為“捕獲”
再按照兒子=>爸爸=>爺爺?shù)捻樞蚩从袩o監(jiān)聽函數(shù)(IE標(biāo)準(zhǔn))稱為“冒泡”
事件綁定api
- IE:
EventTarget.addEvent('onclick',fn)//冒泡
- 網(wǎng)景:
EventTarget.addEventListener('click',fn)//捕獲
- W3C
EventTarget.addEventListener('click',fn,bool)//布爾類型不傳為false會(huì)進(jìn)行冒泡,為true則會(huì)進(jìn)行捕獲
監(jiān)聽代碼中關(guān)于target和currentTarget
event.targrt //用戶操作的元素
event.currentTarget //程序員監(jiān)聽的元素
例如:div>span{文字}辜窑,當(dāng)用戶點(diǎn)擊文字钩述;event.target
就是span,event.currentTarget
就是div
一個(gè)特例
event.addEventListener('click',()=>{
console.log(1)
})
event.addEventListener('click',()=>{
console.log(2)
},true)
那么先輸出的是1還是2呢穆碎?
由于兩者沒有父級(jí)關(guān)系所以也不存在先捕獲后冒泡的順序牙勘,直接按代碼的順序執(zhí)行。
取消冒泡
捕獲的過程是不能夠取消的
event.stopPropagation()//中斷冒泡
不可阻止默認(rèn)動(dòng)作
有些事件不可取消冒泡
MDN中的scroll event
可以看到Bubbles和Cancelable
Bubbles的意思是該事件是否冒泡
Cancelable的意思是開發(fā)者能否取消冒泡
那么應(yīng)該如何阻止scroll呢所禀?
先有滾動(dòng)才有滾動(dòng)事件谜悟,要阻止?jié)L動(dòng)可阻止wheel(鼠標(biāo)滾輪事件)和touchstart(手機(jī)觸屏)的默認(rèn)動(dòng)作,使用CSS中overflow:hidden
直接取消滾動(dòng)條或者滾動(dòng)條width:0w
自定義事件
瀏覽器自帶100多種事件
開發(fā)者也可以在自帶事件之外自定義事件北秽,如:
button.addEventListener('click',()=>{
const event = new CustomEvent('ydz',{
detail:{name:'ydz',age:18},
bubbles:true,
cancelable:false
})
button.dispatchEvent(event)
})
div.addEventListener('ydz',(e)=>{
console.log('ydz觸發(fā)了')
console.log(e.detail)
})
事件委托
什么叫事件委托葡幸?它還有一個(gè)名字叫事件代理,JavaScript高級(jí)程序設(shè)計(jì)上講:事件委托就是利用事件冒泡贺氓,只指定一個(gè)事件處理程序蔚叨,就可以管理某一類型的所有事件。
場景1
需要給100個(gè)按鈕添加點(diǎn)擊事件辙培,怎么辦蔑水?
<div id="div1">
<button>click1</button>
<button>click2</button>
<button>click3</button>
<button>click4</button>
<button>click5</button>
</div> //設(shè)置有100個(gè)button
需要監(jiān)聽這100個(gè)button的祖先,等冒泡的時(shí)候判斷target是不是這100個(gè)button中的一個(gè)
div1.addEventListener('click', (e) => {
const t = e.target
if (t.tagName.toLowerCase() === 'button') {
console.log('button被點(diǎn)擊')
console.log('button的內(nèi)容是' + t.textContent)
}
})
場景2
需要監(jiān)聽目前不存咋的元素點(diǎn)擊事件怎么辦扬蕊?
代碼如上搀别,事件委托
事件委托優(yōu)點(diǎn)
- 省監(jiān)聽數(shù)量
- 可以監(jiān)聽動(dòng)態(tài)元素
封裝事件委托
要求
on('click','#div1','button',()=>{
console.log('button被點(diǎn)擊了')
})
//當(dāng)用戶點(diǎn)擊div1里的元素,要求調(diào)用函數(shù)
封裝事件委托
function on(eventType, element, selector, fn) {
if (!(element instanceof Element)) {
element = document.querySelector(element)
}
element.addEventListener(eventType, (e) => {
const t = e.target
if (t.match(selector)) {
fn(e)
}
})
}