JavaScript 事件流模型及事件委託詳解

JavaScript 中的事件流模型 事件冒泡事件捕獲,以及 事件委託(也叫事件代理),是前端面試中常常出現的知識點,做爲一名前端工程師,梳理基礎知識點對你必定有所幫助。html

文章中全部的代碼都有 codepen 實例,連接在對應的章節內,請同窗們嘗試本身修改運行代碼,以便加深理解。前端

1、名詞解釋

在開始講解以前,咱們先熟悉幾個概念node

事件

事件是能夠被 JavaScript 偵測到的行爲。
onclick onload onchange 等事件。面試

事件流

事件在頁面中的響應順序瀏覽器

事件流模型

爲了更好的理解事件流模型,咱們把 DOM 樹想象成一個靶子,父節點在外,子節點在內。以下圖所示:性能優化

事件流模型 - 靶子

  • 事件冒泡(event bubbling) 由內向外,即從 DOM 樹的子到父,div -> body -> html -> document
  • 事件捕獲(event capturing) 由外向內,即從 DOM 樹的父到子,document -> html -> body -> div

接下來咱們先經過代碼實例詳細講解事件冒泡和事件捕獲,而後講解事件委託,並實現一個事件委託的實例。前端工程師

2、事件冒泡 vs. 事件捕獲

代碼地址: https://codepen.io/cecillia/p...

事件冒泡事件捕獲 分別由 微軟網景 公司提出,後來 W3C 將二者結合,平息了戰火,制定了統一的標準 —— 先捕獲再冒泡函數

addEventListener

在 JavaScript 中,addEventListener 方法用於向指定元素添加事件句柄。
語法:element.addEventListener(event, function, useCapture)性能

element 目標元素
event 事件名,如 click
function 事件觸發時執行的函數
useCapture Bool值,true - 事件句柄在 捕獲 階段執行,false- false- 默認。事件句柄在 冒泡 階段執行

事件冒泡

來看一段代碼實例,思考運行後會彈出什麼。優化

/**.html**/
<div class="t3">document
  <div class="t2">html
    <div class="t1">body
      <div class="t0">div</div>
    </div>
  </div>
</div>

/**.js**/
var $t0 = document.getElementsByClassName('t0')[0];
var $t1 = document.getElementsByClassName('t1')[0];
var $t2 = document.getElementsByClassName('t2')[0];
var $t3 = document.getElementsByClassName('t3')[0];

$t0.addEventListener("click", function(){
  alert("click div")
}, false);

$t1.addEventListener("click", function(){
  alert("click body")
}, false);

$t2.addEventListener("click", function(){
  alert("click html")
}, false);

$t3.addEventListener("click", function(){
  alert("click document")
}, false);

根據冒泡事件流模型由內向外的規則,會依次彈出:click div -> click body -> click html -> click docuement

事件捕獲

將上一段代碼中的 false 都改成 ture,則變爲捕獲方式:

/**.html**/
<div class="t3">document
  <div class="t2">html
    <div class="t1">body
      <div class="t0">div</div>
    </div>
  </div>
</div>

/**.js**/
var $t0 = document.getElementsByClassName('t0')[0];
var $t1 = document.getElementsByClassName('t1')[0];
var $t2 = document.getElementsByClassName('t2')[0];
var $t3 = document.getElementsByClassName('t3')[0];

$t0.addEventListener("click", function(){
  alert("click div")
}, true);

$t1.addEventListener("click", function(){
  alert("click body")
}, true);

$t2.addEventListener("click", function(){
  alert("click html")
}, true);

$t3.addEventListener("click", function(){
  alert("click document")
}, true);

根據捕獲事件流模型由外向內的規則,會依次彈出:click document -> click html -> click body -> click div

事件冒泡&事件捕獲同時存在

若是兩種事件流模型同時存在會怎樣展現呢?

/**.html**/
<div class="t3">document
  <div class="t2">html
    <div class="t1">body
      <div class="t0">div</div>
    </div>
  </div>
</div>

/**.js**/
var $t0 = document.getElementsByClassName('t0')[0];
var $t1 = document.getElementsByClassName('t1')[0];
var $t2 = document.getElementsByClassName('t2')[0];
var $t3 = document.getElementsByClassName('t3')[0];

$t0.addEventListener("click", function(){
  alert("click div")
}, false);

$t1.addEventListener("click", function(){
  alert("click body")
}, false);

$t2.addEventListener("click", function(){
  alert("click html")
}, true);

$t3.addEventListener("click", function(){
  alert("click document")
}, true);

原則:

  • 從外向內,捕獲前進,遇到捕獲事件當即執行
  • 非 target 節點,先捕獲再冒泡
  • target 節點,按代碼書寫順序執行(不管冒泡仍是捕獲)

所以會依次彈出:click document -> click html -> click div -> click body

3、事件流模型的應用:事件委託

代碼地址: https://codepen.io/cecillia/p...

事件委託 又叫 事件代理,指的是利用事件冒泡原理,只需給外層父容器添加事件,若內層子元素有點擊事件,則會冒泡到父容器上,這就是事件委託,簡單說就是:子元素委託它們的父級代爲執行事件。

事件流模型在業務開發中有哪些應用場景呢?

例如,一個播放列表有成千上萬首歌曲,若是遍歷播放列表,給每一個 item 添加點擊事件,而這樣無疑會屢次訪問 DOM,每次 DOM 操做都會引發瀏覽器的重繪與重排,很是不利於性能優化。

這時候咱們能夠利用事件委託,只給最外層的容器添加響應事件,這樣只需一次 DOM 操做,就能達到目的。

/**.html**/
<ul id="music">
  <li>青花瓷</li>
  <li>東風破</li>
  <li>雙節棍</li>
</ul>

/**.js**/
var $music = document.getElementById('music');

$music.addEventListener('click', function(e) {
  if(e.target.nodeName.toLowerCase() === 'li') { // 判斷目標元素target是否爲li元素
    var content = e.target.innerHTML;
    console.log(content);
  }
}, false)

怎麼樣,事件委託也不過如此吧?只要掌握了事件冒泡、事件捕獲的原理,並將其運用到實際業務開發中,就可以真正 get 事件委託這個知識點啦~


【歡迎指正,碼字不易,喜歡請點贊哦】

相關文章
相關標籤/搜索