事件是 JavaScript 與 HTML 互動的基礎。要實現使用者與頁面的互動,先要對目標元素繫結特定的事件、設定事件處理函式,然後使用者觸發事件,事件處理函式執行,產生互動效果。
DOM 事件級別
DOM 級別分為四個級別:DOM0 級、DOM1 級、DOM2 級、DOM3 級;
DOM 事件級別分為三個級別:
- DOM0 級事件
<button id="btn" type="button"></button>
<script>
var btn = document.getElementById('btn')
btn.onclick = function() {
console.log('Hello World')
}
// btn.onclick = null // 解綁事件
</script>
複製程式碼
缺點:無法設定多個事件處理函式
- DOM2 級事件
<button id="btn" type="button"></button>
<script>
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');
}
</script>
複製程式碼
可以為事件設定多個事件處理函式,可以通過第三個引數 ( 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 級事件規定事件流包括三個階段: 事件捕獲(capturing phase)、目標事件(target phase)、事件冒泡(bubbling phase)。
發生的順序是:事件捕獲階段 --> 目標事件階段 --> 事件冒泡階段
事件冒泡
事件開始時由最具體的元素(目標元素)接收,然後逐級向上傳播。
<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 id="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 事件深入淺出(一)