通過上一節的學習,對DOM事件有了一個簡單的瞭解。但這只是學習DOM事件相關知識的起步點。今天來瞭解一下DOM事件的模型。
在Web應用程序或Web網站中,可以通過使用者操作或系統的事件,達到相應的響應。而在JavaScript中,事件在未得到標準化之前,各瀏覽器就有一個事件模型 —— 基本事件模型(Basic Event Model)。
在基本事件模型中,要在某個事件發生時,調用指定的函數,也就是上一節中介紹的事件處理程序。這個程序會指定事件觸發將會做什麼樣的事情。打個比方,當Web頁面加載完所有資源之後,即window
的load
事件中做指定的事情:
window.onload = function () { // window的load事件發生時要做的事情...}
除此之外,事件還可以由使用者的操作一些事情來觸發事件。比如在按鈕上綁定一個click
事件:
<!-- HTML --><button>Click Me!</button>// Scriptlet handler = function () { console.log(this)}document.querySelector('button').onclick = handler
上面的代碼,當用戶用鼠標點擊按鈕時會調用handler()
函數,打印出來的this
就是用戶點擊的按鈕。像這樣的做法,被稱為傳統模型(Traditional Model)或傳統註冊模型(Traditional Registration Model)。這種事件模型也被稱為DOM0級模型。
基本事件模型有一個典型的缺點,就是只能註冊一個事處處理程序,如果你想註冊多個事件處理程序是行不通的。比如:
<!-- HTML --><button>單擊我</button>// Scriptlet handler1 = function () { console.log('Handler1:', this)}let handler2 = function () { console.log('Handler2', this)}document.querySelector('button').onclick = handler1document.querySelector('button').onclick = handler2
當你點擊button
按鈕時,瀏覽器控制台只會輸出hander2()
函數做的事情:
第一個函數handler1()
不起作用。如果你想第一個函數也要起作用,那就需要使用接下來要說的事件模型 —— DOM Level 2模型。
在基本事件模型中,如果要移除監聽函數,可以通過給其事件賦值null
來實現:
document.querySelector('button').onclick = null
DOM level 2模型屬於W3C標準模型,現代瀏覽器都支持該模型。在該事件模型中,一次事件共有三個過程:
document
一直向下傳播到目標元素,依次檢查經歷過的節點是否綁定了事處監聽函數(事件處理程序),如果有則執行,反之不執行document
,依次檢查經過的節點是否綁定了事件監聽函數,如果有則執行,反之不執行。簡而言之:事件一開始從文檔的根節點流向目標對象(捕獲階段),然後在目標對向上被觸發(目標階段),之後再回溯到文檔的根節點(冒泡階段)。
圖片來源於W3C
DOM事件中這三個過程很複雜,但在這篇文章中不做深入闡述,如果感興趣的話,後續的文章將會深入的探討這方面的知識點。
回到DOM Level 2事件模型中,要註冊事件,必須使用addEventListener()
方法。比如下面這個示例:
let handler = function () { // window的load事件要做的事情...}window.addEventListener('load',handler, false)
在基本事件模型中提到過,基本事件模型只能註冊一個事件,但在DOM Level 2事件模型中可以,比如前面提到的按鈕的click
事件,我們可以註冊多個事件:
let handler1 = function () { console.log('handler1:', this)}let handler2 = function () { console.log('handler2', this)}document.querySelector('button').addEventListener('click', handler1, true)document.querySelector('button').addEventListener('click', handler2, true)
這個時候點擊按鈕時,handler1()
和handler2()
兩個函數都會被觸發:
在DOM Level 2事件模型中,如果要移除事件處理程序,可以使用removeEventListener()
方法。
let btn = document.getElementById('btn');btn.addEventListener('click', handler, false);btn.removeEventListener('click', handler, false);
雖然DOM Level 2事件模型是W3C標準事件模型,但低於IE9的瀏覽器是不支持這種事件模型。所以在JavaScript事件模型中,還有第三種事件模型 —— IE事件模型。
在IE事件模型中,需要使用attachEvent()
和detachEvent()
方法來觸發事件和移除事件。在IE事件模型中,其有兩個過程:
document
,依次檢查經過的節點是否綁定了事件監聽函數,如果有則執行DOM Level 3事件模型是DOM Level 2的事件模型的升級版,在DOM Level 2事件模型的基礎上添加了更多的事件類型:
load
、scroll
blur
、focus
dbclick
、mouseup
mousewheel
input
、change
keydown
、keypress
compositionstart
DOMsubtreeModified
同時DOM3級事件也允許使用者自定義一些事件。在自定義事件稱之為自定義事件模型。
事件模型的實現從設計模式的角度來看,是一種觀察者模式或者也叫發佈訂閱模式,訂閱者訂閱一個消息,發佈者發佈這個消息,訂閱者收到消息,這是一種數據流動的方式,使用這個模式的好處是,可以有多個訂閱者,一個發佈者,發佈一條消息,可被多個訂閱者收到。
比如下面這樣的一個事件模型:
;(function(global){ class Events { constructor(){ this.cache = {}; this.onceKeys = []; } on(key, fn){ if(!this.cache[key]) this.cache[key] = []; this.cache[key].push(fn); } one(key, fn){ this.cache[key]=[]; this.on(key, fn); this.onceKeys.push(key); } off(key, fn){ if(this.cache[key]) this.cache[key] = fn ? this.cache[key].filter(v=>v !== fn) : []; } emit(key, ...args){ if(this.cache[key]){ this.cache[key].forEach(v=>v.apply(null, args)) if(this.onceKeys.includes(key)){ this.cache[key] = []; this.onceKeys = this.onceKeys.filter(v=>v!==key); } } } } global.Events = new Events();})(this)
這是一個簡單的自定義事件型型:
on()
用於綁定事件,參數:事件名稱,事件處理函數emit()
用於觸發事件,參數:事件名稱,傳遞給事件處理函數的參數off
用於解除綁定的指定事件, 參數:事件名稱,要解綁的事件函數one
用於綁定一次性事件,只能觸發一次,參數:事件名稱,事件處理函數如果要使用,可以這樣:
Events.on('cus', (a, b) => console.log(a+b))Events.emit('cus', 1, 2); // => 3Events.off('cus');Events.emit('cus', 1, 2)// 只觸發一次Events.one('once', a => console.log(a))Events.emit('once', 1); // => 1Events.emit('once', 2);
從DOM事件模型上,我們可以學到很多。可以在項目中使用類似的解耦的概念。應用中的模塊可以有很高的很複雜度,只要它的複雜度被封裝隱藏在一套簡單的接口背後。很多前端框架(比如Backbone.js
)都是重度基於事件的,使用發佈/訂閱(Publish & Subscribe)的方式來處理跨模塊間的通信,這點跟DOM非常相似。
基於事件的架構是極好的。它提供給我們一套非常簡單通用的接口,通過針對這套接口的開發,我們能完成適應成千上萬不同設備的應用。通過事件,設備們能準確地告訴我們正在發生的事情以及發生的時間,讓我們隨心所欲地做出響應。我們不再顧慮場景背後具體發生的事情,而是通過一個更高層次的抽象來寫出更加令人驚豔的應用。
這篇文章簡單的介紹了DOM事件的模型。在JavaScript中常見的事件模型有:DOM基本事件模型、DOM Level 2事件模型、IE事件模型、DOM Level 3事件模型 和 自定義事件模型。每種事件模型都有其自己獨具的特性。只有瞭解了DOM事件模型之後,才可以為後續的DOM事件打下一個基礎。
如需轉載,煩請註明出處:https://www.w3cplus.com/javascript/dom-model.html
联系客服