最近參考了網上很多關於JS事件捕獲和事件冒泡機制的文章,以下內容為個人對之理解,方便日后查閱。
事件捕獲和事件冒泡是啥?
事件捕獲和事件冒泡分別是Netscape和IE對DOM事件產生順序的描述。Netscape認為DOM接收的事件最先應該是window接收,然后再一節一節往下,最后才是具體的元素接收到事件,即:事件捕獲。而IE則認為DOM事件應該由具體元素最先接收事件,然后再一節一節往上,最后再由window接收事件,即:事件冒泡。最后W3C將兩種方案做了統一,即:把DOM事件分為兩個階段,事件捕獲階段和事件冒泡階段,例如:當頁面某一個元素被點擊,首先是事件捕獲階段,window最先接收事件,然后一節一節往下捕獲,最后由具體元素接收,然后再由具體元素一節一節往上,最后window會再次接收事件,以下為DOM事件流示意圖:
這樣當頁面上一個對象觸發某個事件,我們會有兩次機會對其進行操作!雖然DOM2級事件規范中要求事件捕獲過程中不會涉及事件目標,但是各高版本瀏覽器中都會在事件捕獲過程中觸發對象事件。
在JS事件學習中常常會看到或者聽到事件代理(事件委托)這個說法,那么,什么是事件代理(事件委托)?
什么是事件代理(事件委托)?
看上去很抽象,可以用一個例子來簡單說明其原理:我們在網上購物,我們會留下一個具體地址來接收包裹,但是由於快遞員不能每一件都親自送到我們手中,所以,快遞代收站出現了,快遞員只需要把快遞放在快遞站,然后再繼續派送其他快遞,我們只需要在適當的時機到快遞站取快遞即可。在這個過程中,包裹就是某個事件,快遞員派送的過程就是時間捕獲的過程,適當的時機即事件捕獲到來最底層的具體得到元素,我們去快遞站取快遞就是時間冒泡的過程,所以事件代理(事件委托)就是利用事件冒泡原理在快遞站(父元素)接收我們的快遞(事件),然后我們再去快遞站取款地(事件冒泡)。js中提供了event對象,在這個對象中有個target屬性,通過target屬性我們就能知道具體是哪個元素觸發了事件。
為什么是要使用事件代理(事件委托)?
為什么會有快遞站呢?當然是提高效率,如果快遞員每一件播過都親自送到用戶手中,那效率得多低。事件代理也如此,我們操作DOM的是代價的,應該盡量避免頻繁的操作DOM元素,如果我們給DOM每一個元素都添加事件,理論上沒有任何問題,但是從效率,優化上來講顯得過於麻煩低效。
事件代理簡單DEMO:
<style> 2 li { 3 width: 100px; 4 height: 50px; 5 background-color: pink; 6 } 7 div { 8 width: 80%; 9 height: 80%; 10 background-color: red; 11 } 12 span { 13 display: block; 14 width: 80%; 15 height: 80%; 16 background-color: cyan; 17 18 } 19 a { 20 display: block; 21 width: 80%; 22 height: 80%; 23 background-color: greenyellow; 24 } 25 </style> 26 </head> 27 <body> 28 <ul> 29 <li> 30 <div> 31 <span> 32 <a href="javascript:;">A</a> 33 </span> 34 </div> 35 </li> 36 <li>2</li> 37 <li>3</li> 38 <li>4</li> 39 <li>5</li> 40 <li>6</li> 41 </ul> 42 <script> 43 var ul = document.querySelector('ul'); 44 ul.addEventListener('click', function (e) { 45 console.log(e.target); 46 47 }); 48 </script>
以上代碼只對ul進行了事件監聽,但是當我們分別點擊不同元素時,即使該元素沒有添加事件監聽,同樣會在控制台上顯示我們點擊了這個元素,這就是事件代理(事件委托)。