DOM事件机制
一、簡(jiǎn)介
事件流是一個(gè)事件沿著特定數(shù)據(jù)結(jié)構(gòu)傳播的過(guò)程。冒泡和捕獲是事件流在DOM中兩種不同的傳播方法
事件流有三個(gè)階段
- 事件捕獲階段
- 處于目標(biāo)階段
- 事件冒泡階段
事件捕獲
事件捕獲(event capturing):通俗的理解就是,當(dāng)鼠標(biāo)點(diǎn)擊或者觸發(fā)dom事件時(shí),瀏覽器會(huì)從根節(jié)點(diǎn)開(kāi)始由外到內(nèi)進(jìn)行事件傳播,即點(diǎn)擊了子元素,如果父元素通過(guò)事件捕獲方式注冊(cè)了對(duì)應(yīng)的事件的話,會(huì)先觸發(fā)父元素綁定的事件
事件冒泡
事件冒泡(dubbed bubbling):與事件捕獲恰恰相反,事件冒泡順序是由內(nèi)到外進(jìn)行事件傳播,直到根節(jié)點(diǎn)
示意圖
二、W3C事件模型
因?yàn)橛胁东@和冒泡兩種傳播方式,W3C制定了一個(gè)標(biāo)準(zhǔn)可以讓我們自己選擇使用哪種傳播方式addEventListener('click',fn,?)
第三個(gè)參數(shù)?是一個(gè)bool值,決定使用捕獲或者冒泡
舉個(gè)例子
<div><p>點(diǎn)我看效果</p> </div>當(dāng)你addEventListener函數(shù)第三個(gè)參數(shù)為true時(shí)就表示你使用的是事件捕獲。父級(jí)元素先觸發(fā),子級(jí)元素后觸發(fā),也就是說(shuō)div先觸發(fā),p后觸發(fā)。
當(dāng)你addEventListener函數(shù)第三個(gè)參數(shù)為空或?yàn)閒alse時(shí)就表示你使用的是事件冒泡。子級(jí)元素先觸發(fā),父級(jí)元素后觸發(fā),也就是說(shuō)p先觸發(fā),div后觸發(fā)。
三、Event對(duì)象常見(jiàn)的應(yīng)用
event. preventDefault()阻止默認(rèn)事件
如果調(diào)用這個(gè)方法,默認(rèn)事件行為將不再觸發(fā)。什么是默認(rèn)事件呢?例如表單一點(diǎn)擊提交按鈕(submit)跳轉(zhuǎn)頁(yè)面、a標(biāo)簽?zāi)J(rèn)頁(yè)面跳轉(zhuǎn)或是錨點(diǎn)定位等。
很多時(shí)候我們使用a標(biāo)簽僅僅是想當(dāng)做一個(gè)普通的按鈕,點(diǎn)擊實(shí)現(xiàn)一個(gè)功能,不想頁(yè)面跳轉(zhuǎn),也不想錨點(diǎn)定位。
<a id='a' href='https://baidu.com'>百度</a><script>a.addEventListener("click", function(e){e.preventDefault();}); </script>我們給a添加點(diǎn)擊事件,當(dāng)用戶點(diǎn)擊百度就阻止a標(biāo)簽的默認(rèn)事件,所以點(diǎn)擊后不會(huì)有跳轉(zhuǎn)
event.stopPropagation()阻止事件冒泡
上面提到事件冒泡階段是指事件從目標(biāo)節(jié)點(diǎn)自下而上向window對(duì)象傳播,當(dāng)事件使用event.stopPropagation()方法將阻止事件冒泡到父元素,阻止任何父事件處理程序被執(zhí)行
<div id="hi" style="border: 1px solid red; width: 100px; height: 100px;"><div id="hello" style="border: 1px solid red; width: 50px; height: 50px;"></div> </div><script> hi.addEventListener("click", function(){console.log('hi') });hello.addEventListener("click", function(e){console.log('hello')e.stopPropagation() }); </script>因?yàn)樵谧釉攸c(diǎn)擊事件中使用了event.stopPropagation()阻止冒泡事件,所以最終只打印出了目標(biāo)元素'hello',父元素的'hi'并沒(méi)有被打印出
是否可以阻止冒泡
并不是所有事件都可以阻止冒泡的,具體可以MDN搜索scroll event,看到Bubbles和Cancelable
Bubbles的意思是該事件是否冒泡
Cancelable的意思是開(kāi)發(fā)者是否可以阻止冒泡
event.target & event.currentTarget
- e.target?指向事件觸發(fā)的元素
- e.currentTarget?指向事件綁定的元素
四、事件委托
由于事件會(huì)在冒泡階段向上傳播到父節(jié)點(diǎn),因此可以把子節(jié)點(diǎn)的監(jiān)聽(tīng)函數(shù)定義在父節(jié)點(diǎn)上,由父節(jié)點(diǎn)的監(jiān)聽(tīng)函數(shù)統(tǒng)一處理多個(gè)子元素的事件。這種方法叫做事件委托
優(yōu)點(diǎn)
減少內(nèi)存消耗,提高性能
假設(shè)有一個(gè)?div?,?div?里有大量的?button?,我們需要在點(diǎn)擊每個(gè)?button?的時(shí)候響應(yīng)一個(gè)事件
<div id="container"><button>1</button><button>2</button><button>3</button><button>4</button><button>5</button></div>如果給每個(gè)?button?都綁定一個(gè)函數(shù),那對(duì)于內(nèi)存消耗是非常大的。借助事件代理,我們只需要給父容器div綁定方法即可,這樣不管點(diǎn)擊的是哪一個(gè)后代元素,都會(huì)根據(jù)冒泡傳播的傳遞機(jī)制,把容器的click行為觸發(fā),然后把對(duì)應(yīng)的方法執(zhí)行,根據(jù)事件源,我們可以知道點(diǎn)擊的是誰(shuí),從而完成不同的事。
動(dòng)態(tài)綁定事件
在很多時(shí)候,我們需要通過(guò)用戶操作動(dòng)態(tài)的增刪子元素,如果一開(kāi)始給每個(gè)子元素綁定事件,那么在列表發(fā)生變化時(shí),就需要重新給新增的元素綁定事件,給即將刪去的元素解綁事件,如果用事件委托就會(huì)省去很多這樣麻煩。
實(shí)現(xiàn)
接下來(lái)我們來(lái)實(shí)現(xiàn)上例中父層元素 ?#container? 下的?button?元素的事件委托到它的父層元素上:
<div id="container"><button>1</button><button>2</button><button>3</button><button>4</button><button>5</button> </div><script> container.addEventListener('click', function (e) { //把目標(biāo)元素賦給tlet t = e.target// 判斷是否匹配目標(biāo)元素if (t.nodeName.toLocaleLowerCase() === 'button') {console.log('我是:' + t.textContent);} }); </script>這樣當(dāng)點(diǎn)擊每個(gè)?button?都觸發(fā)事件打印出對(duì)應(yīng)元素的文本內(nèi)容
總結(jié)
- 上一篇: React的组件生命周期
- 下一篇: Shell脚本编程总结