在項目開發時,我們時常需要考慮使用者在使用産品時産生的各種各樣的互動事件,比如滑鼠點選事件、敲擊鍵盤事件等。這樣的事件行為都是前端dom事件的組成部分,不同的dom事件會有不同的觸發條件和觸發效果。本文就将帶大家深入淺出地了解dom事件的那些屬性和方法。
首先在介紹dom事件之前我們先來認識下dom的不同級别。針對不同級别的dom,我們的dom事件處理方式也是不一樣的。
dom級别與dom事件
dom級别一共可以分為4個級别:dom0級,dom1級,dom2級和 dom3級,而dom事件分為3個級别:dom0級事件處理,dom2級事件處理和dom3級事件處理。如下圖所示:
有人可能會問,為什麼沒有dom1級事件處理呢?因為1級dom标準中并沒有定義事件相關的内容,是以沒有所謂的1級dom事件模型。
關于dom級别這裡不做詳細的介紹,下面主要介紹下不同級别dom中的不同僚件。
1.dom0級事件
在了解dom0級事件之前,我們有必要先了解下html事件處理程式,也是最早的這一種的事件處理方式,代碼如下:
<button type="button" onclick="showfn()"></button>
<script>
function showfn() {
alert('hello world');
}
</script>
以上代碼我們通過直接在html代碼裡定義了一個onclick的屬性觸發showfn方法,這樣的事件處理程式最大的缺點就是html于js強耦合,我們一旦需要修改函數名就得修改兩個地方。當然其優點是不需要操作dom來完成事件的綁定。
那麼什麼是dom0級處理事件呢?dom0級事件就是将一個函數指派給一個事件處理屬性,比如:
<button id="btn" type="button"></button>
var btn = document.getelementbyid('btn');
btn.onclick = function() {
// btn.onclick = null; 解綁事件
以上代碼我們給button定義了一個id,通過js擷取到了這個id的按鈕,并将一個函數指派給了一個事件處理屬性onclick,這樣的方法便是dom0級處理事件的展現。我們可以通過給事件處理屬性指派null來解綁事件。
dom0級事件處理程式的缺點在于一個處理程式無法同時綁定多個處理函數,比如我還想在按鈕點選事件上加上另外一個函數。
2.dom2級事件
dom2級事件在dom0級事件的基礎上彌補了一個處理程式無法同時綁定多個處理函數的缺點,允許給一個處理程式添加多個處理函數。代碼如下:
btn.addeventlistener('click', showfn, false);
// btn.removeeventlistener('click', showfn, false); 解綁事件
dom2級事件定義了addeventlistener和removeeventlistener兩個方法,分别用來綁定和解綁事件,方法中包含3個參數,分别是綁定的事件處理屬性名稱(不包含on)、處理函數和是否在捕獲時執行事件處理函數。如果我們還需要添加一個滑鼠移入的方法,隻需要:
btn.addeventlistener('mouseover', showfn, false);
這樣點選按鈕和滑鼠移入時都将觸發showfn方法。
需要注意的是ie8級以下版本不支援addeventlistener和removeeventlistener,需要用attachevent和detachevent來實作:
btn.attachevent('onclick', showfn); // 綁定事件
btn.detachevent('onclick', showfn); // 解綁事件
這裡我們不需要傳入第三個參數,因為ie8級以下版本隻支援冒泡型事件。
3.dom3級事件
dom3級事件在dom2級事件的基礎上添加了更多的事件類型,全部類型如下:
ui事件,當使用者與頁面上的元素互動時觸發,如:load、scroll
焦點事件,當元素獲得或失去焦點時觸發,如:blur、focus
滑鼠事件,當使用者通過滑鼠在頁面執行操作時觸發如:dbclick、mouseup
滾輪事件,當使用滑鼠滾輪或類似裝置時觸發,如:mousewheel
文本事件,當在文檔中輸入文本時觸發,如:textinput
鍵盤事件,當使用者通過鍵盤在頁面上執行操作時觸發,如:keydown、keypress
合成事件,當為ime(輸入法編輯器)輸入字元時觸發,如:compositionstart
變動事件,當底層dom結構發生變化時觸發,如:domsubtreemodified
同時dom3級事件也允許使用者自定義一些事件。
dom事件流
上文中講到了addeventlistener的第三個參數為指定事件是否在捕獲或冒泡階段執行,設定為true表示事件在捕獲階段執行,設定為true表示事件在捕獲階段執行,而設定為false表示事件在冒泡階段執行。那麼什麼是事件冒泡和事件捕獲呢?可以用下圖來解釋:
1.事件冒泡
所謂事件冒泡就是事件像泡泡一樣從最開始生成的地方一層一層往上冒,比如上圖中a标簽為事件目标,點選a标簽後同時也會觸發p、li上的點選事件,一層一層向上直至最外層的html或document。下面是代碼示例:
<div id="box">
<a id="child">事件冒泡</a>
</div>
var box = document.getelementbyid('box'),
child = document.getelementbyid('child');
child.addeventlistener('click', function() {
alert('我是目标事件');
}, false);
box.addeventlistener('click', function() {
alert('事件冒泡至div');
上面的代碼運作後我們點選a标簽,首先會彈出'我是目标事件'提示,然後又會彈出'事件冒泡至div'的提示,這便說明了事件自内而外向上冒泡了。
那麼我們如何阻止事件冒泡呢?這裡就涉及事件的event對象中的stoppropagation方法,如下:
child.addeventlistener('click', function(e) {
e.stoppropagation();
}, false);
加上stoppropagation方法後,我們再次點選a标簽就不會觸發div上的click事件了。
2.事件捕獲
和事件冒泡相反,事件捕獲是自上而下執行,我們隻需要将addeventlistener的第三個參數改為true就行。
}, true);
此時我們點選a标簽,首先彈出的是'事件冒泡至div',其次彈出的是'我是目标事件',正好與事件冒泡相反。
總結
本文主要介紹了不同dom級别下的事件處理程式,同時介紹了事件冒泡和捕獲的觸發原理和方法。熟練地使用不同級别的dom事件并且解決相應的浏覽器相容性問題對我們的前端項目開發會很有幫助。在下篇文章中,我将給大家介紹dom事件中event對象的屬性和方法。
作者:勞蔔
來源:51cto