【JS】DOM事件

  • 給一個孩子元素綁定了click事件,也給爸爸元素綁定了click事件,你點擊了這個孩子元素,你怎麼知道你到底要點擊孩子仍是爸爸(由於孩子是爸爸的一部分,點擊了孩子不就是點擊了爸爸)
  • 因此,點擊了孩子就把爸爸、爺爺、曾爺爺的點擊事件一塊兒觸發了吧
  • 同理,孩子也有孩子,也就是孫子。你想點擊了孩子,可是要是一不當心點到孫子身上,孫子由於是孩子的一部分,也算點到了孩子,就會觸發孩子的事件監聽函數。因此你給孩子綁定了函數,可是觸發函數的多是孫子。
  • 因此,觸發(target)監聽函數的不必定是綁定元素,還多是綁定元素的兒子

事件

定義

  1. 事件是在編程時系統內發生的動做或者發生的事情
  2. 事件是要綁定在元素上的。好比給一個div元素綁定一個鼠標懸浮事件,給一個ol元素綁定鼠標單擊事件。
  3. 可使用事件監聽函數(也叫事件處理程序、偵聽器)來監聽事件,以便事件發生時執行相應的代碼

事件類型舉例(所有事件類型請看MDN文檔)

  • 單擊click
  • 雙擊dblclick
  • 鼠標放置mouseenter
  • 表單內容發生變化
  • 拖拽
  • 頁面滾動
  • 觸發/失去焦點
  • 鍵盤按下
  • 提交表單

DOM事件流

你想一想,若是我按了鍵盤上的空格,是否是也至關於按了整個鍵盤?我按了空格的右下角的英文,是否是至關於按了空格。css

定義

事件流描述的是 從頁面接收事件 的順序。html

事件發生時元素節點之間按照特定的順序傳播,這個過程即DOM事件流。編程

分爲三個階段:一、事件捕獲階段;二、當前目標階段;三、事件冒泡階段

事件捕獲階段(window→觸發元素)

首先開始事件捕獲階段,從DOM樹最根部的節點window開始,沿着DOM樹向下遍歷每一個元素,直到觸發元素目標元素target。若是這些元素也註冊了click事件(且爲捕獲階段),就會執行他們相應的事件監聽函數函數

事件冒泡階段(觸發元素→window)

最後是事件冒泡階段,從觸發元素目標元素target開始,向上逆着遍歷DOM樹,直到最根部window元素。若是這些元素也註冊了click事件(且爲冒泡階段),就會執行他們相應的事件監聽函數性能

例子

咱們爲tr元素綁定了一個單擊click事件。當咱們單擊trui

若單擊的是純tr元素,即觸發元素是純tr元素

  • 綁定元素和觸發元素相同
  • 事件捕獲階段:window → document → html → body → table → tbody → tr
  • 事件冒泡階段:tr → tbody → table → body → html → document → window
  • 路徑(觸發元素到window,也就是冒泡階段):tr → tbody → table → body → html → document → window

若單擊的是tr元素裏的td元素(也是tr元素!!!!),即觸發元素是孩子

  • 綁定元素是觸發元素的爸爸
  • 事件捕獲階段:window → document → html → body → table → tbody → tr → td
  • 事件冒泡階段:td → tr → tbody → table → body → html → document → window
  • 路徑(觸發元素到window,也就是冒泡階段):tr → tbody → table → body → html → document → window

如何給元素綁定事件

方法一:在html的那個元素裏綁定(不要用!)

<div onclick = console.log('hi')>點我</div>this

方法二:給DOM元素的onclick屬性賦值事件監聽函數

$div.onclick = function(e){
    console.log('你剛纔單擊了這個div元素')
}
複製代碼

缺點:一個元素的一種事件(如click)只能有一個事件監聽函數,由於你是給這個元素的這個屬性(onclick)賦值啊!下一個值會覆蓋上一個值的呀。就像我若是要再給$div綁定一個click事件,再寫了一個事件監聽函數。這個事件監聽函數仍是會成爲屬性onclick的新值的呀spa

方法三:調用DOM元素的addEventListener函數

優勢:能夠添加多個事件處理函數。代理

$div.adddEventListener(type,listener,useCapture)

  • type : 事件類型
  • listener : 事件監聽函數
  • useCapture:可選,true表示在捕獲階段調用listener,false(默認)表示在冒泡階段調用listener。

$div.adddEventListener(type,listener,options)

  • options:
  1. 可選,是個對象。
  2. {capture: 是否捕獲階段監聽,once: 是否只監聽一次,passive:是否忽略preventDefault }
  3. 默認全是false

移除事件處理程序target.removeEventListener(type,handler,)

經過addEventListener()添加的事件處理程序只能使用removeEventListener() 來移除;移除時傳入的參數和添加程序處理程序時使用的參數相同。這也意味經過 addEventListener() 添加的匿名函數(沒有傳入參數)將沒法移除 target.removeEventL .istener('click', handler)code

target.removeEventL .istener('click', handler, true)

例子

例子

事件對象

定義理解

var div = document.getElementById('box');
div.onclick = function(event){ };
複製代碼
  1. event在這裏面就是事件對象,寫到事件監聽函數函數的小括號() 裏面,能夠當作形參來看。能夠本身隨便命名(好比 event、e、aa)。後面用不到事件對象的話,就不須要在小括號裏寫。

  2. 事件對象只有有了事件纔會存在,事件對象是系統自動給咱們建立的,不須要咱們傳遞參數(事件對象一定和事件相關,若是沒有事件它就不存在,有了事件就存在了)

  3. 事件對象是 跟事件相關的一系列相關數據的集合 ,好比說 鼠標點擊事件裏面就包含了鼠標相關的信息,如鼠標座標;若是是鍵盤事件裏面就包含了鍵盤事件的信息,好比判斷用戶按下了哪一個鍵。

  4. 我來打印出個事件對象給大家看看,裏面全是此次事件的相關信息,也就是此次事件(對象)的屬性。

常見的事件對象的屬性

  1. e.target:返回觸發事件的元素(不必定是綁定事件的元素,如事件委託)
  2. e.type:返回事件的類型(好比click、mouseover不帶on)
  3. e.preventDefault():該方法阻止默認事件(默認行爲), 好比不讓連接跳轉
  4. e.stopPropagation():中止事件傳播。在這個事件後就沒了,捕獲或者冒泡階段就到此爲止了。
  5. e.path:冒泡路徑,從觸發元素→window

注意:e.target 和 this 的區別

一、e.target 返回的是觸發事件的元素;

二、this 返回的是綁定事件的元素;

區別:e.target 點擊了哪一個元素就返回那個元素;

this 綁定了哪一個元素就返回哪一個元素。那麼就返回誰。

有的時候,事件的綁定元素和觸發元素不是同一個。

例子

  • div綁定了單擊事件,那麼this指向的就是dive.target 指向咱們點擊的那個對象(那個元素觸發的對象),點擊的是div,因此e.target 指向的就是div----綁定元素和觸發元素相同

  • ul綁定了單擊事件,那麼this指向的就是ul;e.target 指向咱們點擊的那個對象(那個元素觸發的對象),點擊的是紅框右上角,就是ul,因此e.target 指向的就是ul---綁定元素和觸發元素相同

  • ul綁定了單擊事件,那麼this指向的就是ul;e.target 指向咱們點擊的那個對象(那個元素觸發的對象),點擊的是li,因此e.target 指向的就是li---綁定元素和觸發元素不一樣

事件委託

  • 事件委託,通俗地來說,就是把一個元素響應事件(click、keydown......)的函數委託到另外一個元素;
  • 通常來說,會把一個或者一組元素的事件委託到它的父層或者更外層元素上,真正綁定事件的是外層元素,當事件響應到須要綁定的元素上時,會經過事件冒泡機制從而觸發它的外層元素的綁定事件上,而後在外層元素上去執行函數。
  • 事件綁定代理給父元素,由父元素根據事件來源統一處 理
  • 適用於可能會新增子元素對場景
  • 事件代理其實是事件冒泡的應用
  • 若是在須要有多個DOM事件須要監聽的狀況下(好比幾百條微博點擊事件註冊),給每個DOM都綁定監聽函數,對性能會有極大的影響,所以,有一解決方案爲事件委託。
  • 事件委託利用了事件冒泡與event.target

委託的優勢

  1. 減小內存消耗

試想一下,若果咱們有一個列表,列表之中有大量的列表項,咱們須要在點擊列表項的時候響應一個事件;

<ul id="list">
  <li>item 1</li>
  <li>item 2</li>
  <li>item 3</li>
  ......
  <li>item n</li>
</ul>
// ...... 表明中間還有未知數個 li
複製代碼

若是給每一個列表項一一都綁定一個函數,那對於內存消耗是很是大的,效率上須要消耗不少性能;

所以,比較好的方法就是把這個點擊事件綁定到他的父層,也就是 ul 上,而後在執行事件的時候再去匹配判斷目標元素;

因此事件委託能夠減小大量的內存消耗,節約效率。

  1. 動態綁定事件

好比上述的例子中列表項就幾個,咱們給每一個列表項都綁定了事件; 在不少時候,咱們須要經過 AJAX 或者用戶操做動態的增長或者去除列表項元素,那麼在每一次改變的時候都須要從新給新增的元素綁定事件,給即將刪去的元素解綁事件;

若是用了事件委託就沒有這種麻煩了,由於事件是綁定在父層的,和目標元素的增減是沒有關係的,執行到目標元素是在真正響應執行事件函數的過程當中去匹配的;

因此使用事件在動態綁定事件的狀況下是能夠減小不少重複工做的。

jQuery 中的事件委託

  1. $.on: 基本用法: $('.parent').on('click', 'a', function () { console.log('click event on tag a'); }),它是.parent 元素之下的a 元素的事件代理到$('.parent') 之上,只要在這個元素上有點擊事件,就會自動尋找到 .parent 元素下的 a 元素,而後響應事件;
  2. $.delegate: 基本用法: $('.parent').delegate('a', 'click', function () { console.log('click event on tag a'); }),同上,而且還有相對應的 $.delegate來刪除代理的事件;
相關文章
相關標籤/搜索