DOM 事件詳解
事件是 JavaScript 與 HTML 互動的基礎。要實現使用者與頁面的互動,先要對目標元素繫結特定的事件、設定事件處理函式,然後使用者觸發事件,事件處理函式執行,產生互動效果。
DOM 事件級別
DOM 級別分為四個級別:DOM0 級、DOM1 級、DOM2 級、DOM3 級;

DOM 事件級別分為三個級別:
- DOM0 級事件
<button id="btn" type="button"></button> var btn = document.getElementById('btn') btn.onclick = function() { console.log('Hello World') } // btn.onclick = null // 解綁事件 複製程式碼
缺點:無法設定多個事件處理函式
- DOM2 級事件
<button id="btn" type="button"></button> var btn = document.getElementById('btn'); btn.addEventListener('click', showFn, false) btn.addEventListener('click', showFn2, false) // btn.removeEventListener('click', showFn, false) // 解綁事件 function showFn() { alert('Hello World'); } function showFn2() { alert('Hello World2'); } 複製程式碼
可以為事件設定多個事件處理函式,可以通過第三個引數 ( useCapture ) 設定在什麼階段執行事件處理函式,預設是 false, 即在事件冒泡階段執行事件處理函式。
需要注意的是在 IE8 及以下版本需要用 attachEvent
和 detachEvent
實現,只有兩個引數,事件名需要以 on 開頭,只支援在事件冒泡階段執行事件處理函式。
- DOM3 級事件
DOM3 級事件是在 DOM2 級事件的基礎上添加了更多的事件型別,允許自定義事件。
- UI事件,當用戶與頁面上的元素互動時觸發,如:load、scroll
- 焦點事件,當元素獲得或失去焦點時觸發,如:blur、focus
- 滑鼠事件,當用戶通過滑鼠在頁面執行操作時觸發如:dbclick、mouseup
- 滾輪事件,當使用滑鼠滾輪或類似裝置時觸發,如:mousewheel
- 文字事件,當在文件中輸入文字時觸發,如:textInput
- 鍵盤事件,當用戶通過鍵盤在頁面上執行操作時觸發,如:keydown、keypress
- 合成事件,當為IME(輸入法編輯器)輸入字元時觸發,如:compositionstart
- 變動事件,當底層DOM結構發生變化時觸發,如:DOMsubtreeModified
// 自定義事件 var event = new Event('test') // 給元素繫結事件 domElement.addEventListener('test', function() { console.log('event test') },) // 觸發事件 setTimeout(function() { domElement.dispatchEvent(event) }, 1000) 複製程式碼
DOM 事件流
想象畫在一張紙上的一組同心圓。如果把手指放在圓心上,那麼手指指向的不是一個圓,而是紙上的所有圓。所以如果單擊了某個按鈕單擊事件不僅僅發生在這個按鈕上,甚至也單擊了整個頁面。
事件流又稱為事件傳播,描述的是從頁面中接收事件的順序。DOM2 級事件規定事件流包括三個階段: 事件捕獲(capture phase) 、 目標事件(target phase) 、 事件冒泡(bubblingphase) 。
發生的順序是:事件捕獲階段 --> 目標事件階段 --> 事件冒泡階段

事件冒泡
事件開始時由最具體的元素(目標元素)接收,然後逐級向上傳播。
<style> #parent { width: 200px; height: 200px; background-color: green; } #child { width: 100px; height: 100px; background-color: yellow; } </style> <div id="parent"> <div id="child">目標元素</div> 父級元素 </div> <script> var parent = document.getElementById('parent') var child = document.getElementById('child') parent.addEventListener('click', function(e) { console.log('parent bubbling') }, false) child.addEventListener('click', function() { console.log('target bubbling') }, false) document.body.addEventListener('click', function() { console.log('body bubbling') }, false) document.documentElement.addEventListener('click', function() { console.log('html bubbling') }, false) document.addEventListener('click', function() { console.log('document bubbling') }, false) window.addEventListener('click', function() { console.log('window bubbling') }, false) </script> 複製程式碼
執行結果:

事件冒泡
事件按 window -> document -> html -> body -> ... -> 目標元素 的方向向下層元素傳遞。
<style> #parent { width: 200px; height: 200px; background-color: green; } #child { width: 100px; height: 100px; background-color: yellow; } </style> <div id="parent"> <div id="child">目標元素</div> 父級元素 </div> <script> var parent = document.getElementById('parent') var child = document.getElementById('child') parent.addEventListener('click', function(e) { console.log('parent capture') }, true) child.addEventListener('click', function() { console.log('target capture') }, true) document.body.addEventListener('click', function() { console.log('body capture') }, true) document.documentElement.addEventListener('click', function() { console.log('html capture') }, true) document.addEventListener('click', function() { console.log('document capture') }, true) window.addEventListener('click', function() { console.log('window capture') }, true) </script> 複製程式碼
執行結果:

事件物件引數 event
在使用者觸發事件,執行事件處理函式的時候,預設會向事件處理函式傳入一個 event 物件,它記錄了該事件的狀態和行為。
event 常用屬性和方法
type target currentTarget stopPropagation() preventDefault()
target、currentTarget 與 this
<div id="parent"> <div="child"></div> </div> <script> var parent = document.getElementById('parent') function handler(e) { console.log(e.target) console.log(e.currentTarget) console.log(this) } parent.addEventListener('click', handler, false) </script> 複製程式碼
當點選 parent 時,輸出:
1 <div id="parent">...</div> 2 <div id="parent">...</div> 3 <div id="parent">...</div> 複製程式碼
當點選 child 時,輸出:
1 <div id="child">...</div> 2 <div id="parent">...</div> 3 <div id="parent">...</div> 複製程式碼
所以 target
是事件發出者, curentTarget
是事件監聽者,事件處理函式中的 this
等同於 e.currentTarget
event 物件的一些相容性寫法
- 獲得 event
// 事件處理函式 function handleClick(event) { var e = event || window.event ··· } 複製程式碼
- 獲得 target
··· var target = e.target || e.srcElement ··· 複製程式碼
- 阻止瀏覽器預設行為
··· e.preventDefault ? e.preventDefault() : (e.returnValue = false) ··· 複製程式碼
- 阻止冒泡
··· e.stopPropagation ? e.stopPropagation() : (e.cancelBubble = true) ··· 複製程式碼
- 事件繫結與解綁
function addEvent(element, type, fn) { element.addEventListener ? element.addEventListener(type, fn, false) : element.attachEvent('on'+ type, fn) } function removeEvent(element, type, fn) { element.removeEventListener ? element.removeEventListener(type, fn, false) : element.detachEvent('on'+ type, fn) } 複製程式碼
屬性表
- 基礎屬性
屬性 | 描述 |
---|---|
altKey | 返回當事件被觸發時,”ALT” 是否被按下。 |
button | 返回當事件被觸發時,哪個滑鼠按鈕被點選。 |
clientX | 返回當事件被觸發時,滑鼠指標的水平座標。 |
clientY | 返回當事件被觸發時,滑鼠指標的垂直座標。 |
ctrlKey | 返回當事件被觸發時,”CTRL” 鍵是否被按下。 |
metaKey | 返回當事件被觸發時,”meta” 鍵是否被按下。 |
relatedTarget | 返回與事件的目標節點相關的節點。 |
screenX | 返回當某個事件被觸發時,滑鼠指標的水平座標。 |
screenY | 返回當某個事件被觸發時,滑鼠指標的垂直座標。 |
shiftKey | 返回當事件被觸發時,”SHIFT” 鍵是否被按下。 |
- IE 屬性
屬性 | 描述 |
---|---|
cancelBubble | 如果事件控制代碼想阻止事件傳播到包容物件,必須把該屬性設為 true。 |
fromElement | 對於 mouseover 和 mouseout 事件,fromElement 引用移出滑鼠的元素。 |
keyCode | 對於 keypress 事件,該屬性聲明瞭被敲擊的鍵生成的 Unicode 字元碼。對於 keydown 和 keyup |
offsetX,offsetY | 發生事件的地點在事件源元素的座標系統中的 x 座標和 y 座標。 |
returnValue | 如果設定了該屬性,它的值比事件控制代碼的返回值優先順序高。把這個屬性設定為 false 可以阻止瀏覽器預設行為 |
srcElement | 對於生成事件的 Window 物件、Document 物件或 Element 物件的引用。 |
toElement | 對於 mouseover 和 mouseout 事件,該屬性引用移入滑鼠的元素。 |
x,y | 事件發生的位置的 x 座標和 y 座標,它們相對於用CSS動態定位的最內層包容元素。 |
- 標準 event 屬性(2級 DOM 事件標準定義的屬性)
屬性或方法 | 描述 |
---|---|
bubbles | 返回布林值,指示事件是否是冒泡事件型別。 |
cancelable | 返回布林值,指示事件是否可擁可取消的預設動作。 |
currentTarget | 返回其事件監聽器觸發該事件的元素。 |
eventPhase | 返回事件傳播的當前階段。 |
target | 返回觸發此事件的元素(事件的目標節點)。 |
timeStamp | 返回事件生成的日期和時間。 |
type | 返回當前 Event 物件表示的事件的名稱。 |
initEvent() | 初始化新建立的 Event 物件的屬性。 |
preventDefault() | 通知瀏覽器不要執行與事件關聯的預設動作。 |
stopPropagation() | 不再派發事件(常用於阻止事件冒泡)。 |
閱讀原文 參考:#事件流理解 、# javascript event(事件物件)詳解 、# DOM 事件深入淺出(一)