JavaScript學習筆記(十五) 事件模型

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學習筆記

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章