0、DOM 標準
在開始學習 JavaScript 事件模型前,我們首先來了解一下什麼是 DOM(Document Object Model)
簡單來說,DOM 是 W3C 定義的訪問 HTML 和 XML 文檔的標準
按照不同的發展階段,分爲不同的級別,分別是 DOM0、DOM1、DOM2、DOM3
DOM0、DOM2、DOM3 都有定義與事件相關的內容,但是 DOM1 沒有定義與事件相關的內容
1、事件模型
(1)事件捕獲
事件從文檔對象上開始,然後往下傳遞,直到目標對象(從父到子),低版本瀏覽器不支持事件捕獲
<!DOCTYPE html>
<html>
<head>
<title>事件捕獲</title>
</head>
<body>
<ul>
<li>Apple</li>
<li>Banana</li>
<li>Cherry</li>
</ul>
</body>
<script>
let html = document.documentElement
html.addEventListener('click', () => { console.log('html') }, true)
let body = document.body
body.addEventListener('click', () => { console.log('body') }, true)
let uls = document.getElementsByTagName('ul')
for (let ul of uls) { ul.addEventListener('click', () => { console.log('ul') }, true) }
let lis = document.getElementsByTagName('li')
for (let li of lis) { li.addEventListener('click', () => { console.log('li') }, true) }
// 點擊列表項,打印結果爲:html body ul li
</script>
</html>
(2)事件冒泡
事件從目標對象上開始,然後往上傳遞,直到文檔對象(從子到父),所有的瀏覽器都支持事件冒泡
<!DOCTYPE html>
<html>
<head>
<title>事件冒泡</title>
</head>
<body>
<ul>
<li>Apple</li>
<li>Banana</li>
<li>Cherry</li>
</ul>
</body>
<script>
let html = document.documentElement
html.addEventListener('click', () => { console.log('html') }, false)
let body = document.body
body.addEventListener('click', () => { console.log('body') }, false)
let uls = document.getElementsByTagName('ul')
for (let ul of uls) { ul.addEventListener('click', () => { console.log('ul') }, false) }
let lis = document.getElementsByTagName('li')
for (let li of lis) { li.addEventListener('click', () => { console.log('li') }, false) }
// 點擊列表項,打印結果爲:li ul body html
</script>
</html>
(3)事件流模型
DOM2 定義了事件流模型,這是目前廣泛使用的 JavaScript 事件模型,規定事件傳遞先捕獲後冒泡
<!DOCTYPE html>
<html>
<head>
<title>事件流模型</title>
</head>
<body>
<ul>
<li>Apple</li>
<li>Banana</li>
<li>Cherry</li>
</ul>
</body>
<script>
let html = document.documentElement
html.addEventListener('click', () => { console.log('Chtml') }, true)
html.addEventListener('click', () => { console.log('Bhtml') }, false)
let body = document.body
body.addEventListener('click', () => { console.log('Cbody') }, true)
body.addEventListener('click', () => { console.log('Bbody') }, false)
let uls = document.getElementsByTagName('ul')
for (let ul of uls) { ul.addEventListener('click', () => { console.log('Cul') }, true) }
for (let ul of uls) { ul.addEventListener('click', () => { console.log('Bul') }, false) }
let lis = document.getElementsByTagName('li')
for (let li of lis) { li.addEventListener('click', () => { console.log('Cli') }, true) }
for (let li of lis) { li.addEventListener('click', () => { console.log('Bli') }, false) }
// 點擊列表項,打印結果爲:Chtml Cbody Cul Cli Bli Bul Bbody Bhtml
</script>
</html>
2、事件處理程序
(1)DOM0 事件處理程序
通過事件監聽函數指定事件處理程序,事件處理程序在冒泡階段執行
<button id="submit">提交</button>
<script>
var button = document.getElementById('submit')
// 對於 DOM0 事件處理函數,this 指向目標對象,這裏 this 指向 button
var handleEvent = function(e) { console.log(this) }
// 添加事件處理函數 button.onclick = handleEvent
// 刪除事件處理函數 button.onclick = null
button.onclick = handleEvent
</script>
DOM0 事件處理程序,同一個事件只能綁定一個事件處理函數,後面綁定的處理函數會覆蓋前面綁定的處理函數
<button id="submit">提交</button>
<script>
var button = document.getElementById('submit')
var sayHello = function(e) { console.log('Hello') }
var sayGoodbye = function(e) { console.log('Goodbye') }
button.onclick = sayHello
button.onclick = sayGoodbye
// 只會打印 Goodbye
</script>
(2)DOM2 事件處理程序
通過 addEventListener()
添加事件處理程序,通過 removeEventListener()
刪除事件處理程序
它們都接收三個參數,分別是事件名稱、事件處理函數以及一個布爾類型的值,這個布爾值默認爲 false
如果布爾值爲 false,則在冒泡階段執行處理函數,如果布爾值爲 true,則在捕獲階段執行處理函數
<button id="submit">提交</button>
<script>
var button = document.getElementById('submit')
// 對於 DOM2 事件處理函數,this 指向目標對象,這裏 this 指向 button
var handleEvent = function(e) { console.log(this) }
// 添加事件處理函數 button.addEventListener('click', handleEvent)
// 刪除事件處理函數 button.removeEventListener('click', handleEvent)
button.addEventListener('click', handleEvent)
</script>
DOM2 事件處理程序,同一個事件可以綁定多個事件處理函數,先綁定先執行
<button id="submit">提交</button>
<script>
var button = document.getElementById('submit')
var sayHello = function(e) { console.log('Hello') }
var sayGoodbye = function(e) { console.log('Goodbye') }
button.addEventListener('click', sayHello)
button.addEventListener('click', sayGoodbye)
// 先打印 Hello,再打印 Goodbye
</script>
(3)低版本 IE 事件處理程序(IE9 之前)
通過 attachEvent()
添加事件處理程序,通過 detachEvent()
刪除事件處理程序
它們都接收兩個參數,分別是事件監聽函數名稱以及事件處理函數,將在冒泡階段執行處理函數
<button id="submit">提交</button>
<script>
var button = document.getElementById('submit')
// 對於低版本 IE 事件處理函數,this 指向全局對象,這裏 this 指向 window
var handleEvent = function() { console.log(this) }
// 添加事件處理函數 button.attachEvent('onclick', handleEvent)
// 刪除事件處理函數 button.detachEvent('onclick', handleEvent)
button.attachEvent('onclick', handleEvent)
</script>
低版本 IE 事件處理程序,同一個事件可以綁定多個事件處理函數,先綁定後執行
<button id="submit">提交</button>
<script>
var button = document.getElementById('submit')
var sayHello = function() { console.log('Hello') }
var sayGoodbye = function() { console.log('Goodbye') }
button.attachEvent('onclick', sayHello)
button.attachEvent('onclick', sayGoodbye)
// 先打印 Goodbye,再打印 Hello
</script>
3、事件類型
HTML 與 JavaScript 通過事件進行交互,常見的事件如下:
(1)鼠標事件
mousedown
:在按下鼠標按鍵時觸發mouseup
:在鬆開鼠標按鍵時觸發click
:在點擊鼠標時觸發dblclick
:在雙擊鼠標時觸發mouseenter
:在鼠標移入特定範圍時觸發mouseleave
:在鼠標移出特定範圍時觸發mousemove
:鼠標在特定範圍內移動時觸發mouseover
:鼠標移到某元素上觸發mouseout
:鼠標從某元素移開觸發
(2)鍵盤事件
keydown
:在按下鍵盤按鍵時觸發keyup
:在鬆開鍵盤按鍵時觸發keypress
:在按住鍵盤按鍵時觸發
(3)UI 事件
load
:在文檔或圖像加載完成後觸發unload
:在文檔或圖像銷燬完成後觸發error
:加載文檔或圖像時發生錯誤abort
:加載文檔或圖像時出現中斷scroll
:在滾動滾動條時觸發resize
:調整窗口大小時觸發
(4)焦點事件
focus
:在元素獲得焦點時觸發,事件不冒泡blur
:在元素失去焦點時觸發,事件不冒泡
(5)表單事件
select
:在被選定時觸發change
:在被修改時觸發submit
:在被提交時觸發
4、事件對象
當一個事件被觸發時,會產生一個事件對象,這個事件對象會隱式傳入事件處理函數
因此,我們可以在事件處理函數中通過事件對象的屬性和方法獲取事件的相關信息
(1)事件對象的常用屬性
type
:事件名稱target
:觸發事件的目標元素currentTarget
:觸發事件的當前元素bubbles
:事件是否爲冒泡類型cancelBubble
:是否取消冒泡行爲cancelable
:是否能調用preventDefault()
方法取消默認行爲defaultPrevented
:是否有調用preventDefault()
方法eventPhase
:事件傳播的階段timeStamp
:觸發事件的時間clientX
:鼠標指針相對於瀏覽器頁面的水平座標
clientY
:鼠標指針相對於瀏覽器頁面的垂直座標screenX
:鼠標指針相對於屏幕的水平座標screenY
:鼠標指針相對於屏幕的垂直座標shiftKey
:“SHIFT” 鍵是否被按下ctrlKey
:“CTRL” 鍵是否被按下altKey
:“ALT” 鍵是否被按下metaKey
:“meta” 鍵是否被按下
(2)事件對象的常用方法
preventDefault
:阻止默認行爲stopPropagation
:阻止事件傳播
【 閱讀更多 JavaScript 系列文章,請看 JavaScript學習筆記 】