DOM(Document Object Model,文檔對象模型)是針對HTML文檔和XML文檔的一個API。DOM描繪了一個層次化的節點樹,允許開發人員添加、移出和修改頁面的某一部分,DOM脫胎于Netscape及微軟公司創始的DHTML(動態HTML)。但現在它已經成為表現和操作頁面標記的真正跨平臺、語言中立的方式。
Netscape Navigator 4和IE4分別發布于1997年的6月和10月發布的DHTML,由于IE4和Netscape Navigator4分別支持不同的DHTML,為了統一標準,W3C開始制定DOM。1998年10月W3C總結了IE和 Navigator4的規范,制定了DOMLevel 1即DOM1,之前IE與Netscape的規范則被稱為DOMLevel 0即DOM0。
DOM0級事件
假設頁面中存在一個btn的按鈕,并且給btn添加一個點擊事件
btn.onclick = function(){
console.log('this is a click event')
}
事件就是用戶或瀏覽器自身執行的某種操作,如click、load、mouseover等,都是事件的名字,而響應某個事件的函數就被稱為事件處理程序。
click事件過程
在上述的例子中,click事件并沒有像其他函數一樣,必須要調用才可以執行,click事件并不確定什么時候發生,而當瀏覽器發現用戶點擊該按鈕時,瀏覽器就檢測btn.onclick
是否有值,如果有,就會執行btn.onclick.call(btn,event)
,此時函數執行,call()方法接收兩個參數,第一個指向調用當前方法的對象,也就是this
。
需要注意的是,指定的this值并不一定是該函數執行時真正的this值,如果這個函數處于非嚴格模式下,則指定為null和undefined的this值會自動指向全局對象(瀏覽器中就是window對象),同時值為原始值(數字,字符串,布爾值)的this會指向該原始值的自動包裝對象。
另一個參數則是事件對象event
,該對象也可以通過arguments[0]
來訪問,它包含了事件相關的所有信息,如本例子中,則包含了點擊事件的全部信息。可以通過給函數傳參來獲取事件信息。
btn.onclick = function(e){
console.log('this is a click event');
console.log(e); // 事件對象
}
但是在IE中,在使用DOM0級方法添加事件處理程序時,event
是作window
對象的一個屬性而存在的。此時訪問事件對象需要通過window.event
。
btn.onclick = function(){
console.log(window.event); // IE中事件對象
}
在DOM0級中,如果想要實現一個對象綁定多個函數,可以這樣實現。
function fn1(){
// do something
}
function fn2(){
// do something
}
btn.onclick = function(e){
fn1.call(this,xxx);
fn2.call(this.yyy);
}
DOM2級事件
W3C后來將DOM1升級為DOM2,DOM2級規范開始嘗試以一種符合邏輯的方式來標準化DOM事件。DOM0級可以認為onclick是btn的一個屬性,DOM2級則將屬性升級為隊列。
DOM2級事件定義了兩個方法,用于處理指定和刪除事件處理程序的操作,addEventListener()
和removeEventListener()
,所有的DOM節點中都包含這兩個方法,它們都接收3個參數
- 要處理的事件名
- 作為事件處理程序的函數
- 布爾值,
true
代表在捕獲階段調用事件處理程序,false表示在冒泡階段調用事件處理程序,默認為false
。
btn.addEventListener('click',function(){
// do something
})
btn.addEventListener('click',function(){
// do something else
})
addEventListener()
將事件加入到監聽隊列中,當瀏覽器發現用戶點擊按鈕時,click隊列中依次執行匿名函數1、匿名函數2。
function fn1(){
// do something
}
function fn1(){
// do something else
}
btn.addEventListener('click',fn1)
btn.addEventListener('click',fn2)
如果這樣寫,click隊列中依次fn1.call(btn,event)
,fn2.call(btn,event)
。
通過addEventListener()
添加的事件只能由removeEventListener()
來移除,并且removeEventListener()
只能移除具名函數,不能移除匿名函數。
IE中DOM2級事件
IE8及之前,實現類似addEventListener()
和removeEventListener()
的兩個方法是attachEvent()
和detachEvent()
,這兩個方法接受相同的兩個參數
- 要處理的事件名
- 作為事件處理程序的函數
IE8之前的只支持事件冒泡,所以通過attachEvent()添加的事件處理程序只能添加到冒泡階段。
btn.attachEvent('click',fn1)
btn.attachEvent('click',fn2)
當用戶點擊時,click隊列依次fn1.call(undefined,undefined)
,fn2.call(undefined,undefined)
。
類似的detachEvent()也只能移除具名函數,不能移除匿名函數。
兼容處理
if(typeof btn.addEventListener === 'function'){
btn.addEventListener('click',fn);
}else if(typeof btn.attachEvent === 'function'){
btn.attachEvent('onclick',fn)
}else{
btn.onclick=function(){
// do something
}
}