理解:javascript中DOM0,DOM2,DOM3級事件模型

javascript中的事件

  • javascript程序使用的是事件驅動的設計模式,爲一個元素添加事件監聽函數,當這個元素的相應事件被觸發那麼其添加的事件監聽函數就被調用:事件是javascript和HTML交互基礎, 任何文檔或者瀏覽器窗口發生的交互, 都要經過綁定事件進行交互;
  • 全部瀏覽器都支持DOM0級事件處理程序,且使用該方式時,事件處理程序是在元素的做用域中運行,所以程序中的this都是指向元素。

如何理解DOM0,DOM2,DOM3

文檔對象模型是一種與編程語言及平臺無關的API(Application programming Interface),藉助於它,程序可以動態地訪問和修改文檔內容、結構或顯示樣式。javascript

W3C協會早在1988年就開始了DOM標準的制定,W3C DOM標準能夠分爲DOM1,DOM2,DOM3三個版本。html

DOM1級主要定義的是HTML和XML文檔的底層結構。java

DOM2和DOM3級別則在這個結構的基礎上引入了更多的交互能力,也支持了更高級的XML特性。爲此DOM2和DOM3級分爲許多模塊(模塊之間具備某種關聯),分別描述了DOM的某個很是具體的子集。這些模塊以下:編程

  1. DOM2級核心(DOM Level 2 Core):在1級核心的基礎上構建,爲節點添加了更多方法和屬性;
  2. DOM2級視圖(DOM Level 2 Views):爲文檔定義了基於樣式信息的不一樣視圖;
  3. DOM2級事件(DOM Level 2 Style):定義瞭如何以編程方式來訪問和改變CSS樣式信息;
  4. DOM2級遍歷和範圍(DOM Level 2 Traversal and Range):引入了遍歷DOM文檔和選擇其特定部分的新接口。 
  5. DOM2級HTML(DOM Level 2 HTML):在1級HTML基礎上構建,添加了更多屬性、方法和新接口。
  6. DOM3級又增長了XPath模塊和加載與保存(Load and Save)模塊。

DOM2級和3級的目的在於擴展DOM API,以知足操做XML的全部需求,同時提供更好的錯誤處理及特性檢測能力。 DOM0就是直接經過 onclick寫在html裏面的事件;設計模式

DOM2是經過addEventListener綁定的事件, 還有IE下的DOM2事件經過attachEvent綁定; DOM3是一些新的事件。瀏覽器

0級DOM:

一開始瀏覽器處理事件的時候只有原始事件模型,事件處理程序被設置爲js代碼串做爲html的性質值,例如:bash

<input id="myButton" type="button" value="Press Me" onclick="alert('thanks');">複製代碼

在js中html元素都有一個對應的對象,這個對象的屬性對應那個html元素的性質,因此能夠用js代碼添加事件監聽函數
服務器

document.getElementById("myButton").onclick = function () {
        alert('thanks');
}複製代碼

一般狀況下事件監聽函數若是返回一個值而且是false,則會阻止瀏覽器執行默認的動做。閉包

不管用html仍是js,都是把一個函數賦值給文檔元素,在事件監聽函數被調用時候它是做爲產生事件的元素的放法調用的,因此this引用的是那個目標元素(例子中的Input對象)。
從技術上來講,W3C的DOM標準並不支持上述最原始的添加事件監聽函數的方式,這些都是在DOM標準造成前的事件模型。儘管沒有正式的W3C標準,但這種事件模型仍然獲得普遍應用,這就是咱們一般所說的0級DOM。框架

2級DOM:

DOM1級於1998年10月1日成爲W3C推薦標準。

1級DOM標準中並無定義事件相關的內容,因此沒有所謂的1級DOM事件模型。

在2級DOM中除了定義了一些DOM相關的操做以外還定義了一個事件模型 ,這個標準下的事件模型就是咱們所說的2級DOM事件模型

2級DOM的事件傳播
在2級DOM中,當事件發生在節點時,目標元素的事件處理函數就被觸發,並且目標的每一個祖先節點也有機會處理那個事件。由於2級DOM的事件傳播分三個階段進行。


  1. 第一,在capturing階段,事件從Document對象沿着文檔樹向下傳播給節點。若是目標的任何一個祖先專門註冊了事件監聽函數,那麼在事件傳播的過程當中就會運行這些函數。
  2. 第二,階段發生在目標節點自身,直接註冊在目標上的適合的事件監聽函數將運行。
  3. 第三,階段是bubbling階段,這個階段事件將從目標元素向上傳播回Document對象(與capturing相反的階段)。雖然全部事件都受capturing階段的支配,但並非全部類型的事件都bubbling。(0級DOM事件模型處理沒有capturing階段) 
事件對象

在觸發DOM上的某個事件時,會產生一個事件對象event,這個對象中包含着全部與事件有關的信息。

包括事件的元素、事件的類型,以及其餘與特定事件相關的信息。

例如,鼠標操做事件,包含鼠標的位置信息,鍵盤操做事件包含按下的鍵的信息。全部瀏覽器都支持event對象,但支持方式不一樣。

IE的事件流是冒泡, 從裏面往上面冒, netscape是從外部元素往內部元素捕獲; 而DOM2級的事件規定了事件流包含三個階段包括: 1:事件捕獲, 2:處於目標階段, 3:事件冒泡階段(IE8以及更早版本不支持DOM事件流);

不管在DOM0仍是DOM2仍是DOM3中都會在事件函數中傳入事件對象;

<script type="text/javascript"> 
    var p = document.getElementById('p'); 
    p.addEventListener("click",function(){
         console.log(arguments[0]); 
    })
</script>複製代碼

點擊a後capturing階段事件傳播會從document-> span->a,而後發生在a,最後bubbling階段事件傳播會從a->span->document 。

2級DOM的事件監聽函數註冊

2級事件模型中,能夠調用對象的addEventListener()方法爲元素設置事件監聽函數,也就是說經過2級DOM的這個API註冊的函數纔有可能在上述事件傳播三個階段中任意一個階段捕捉到事件的發生(若是用0級DOM的2個方法賦值的事件監聽函數不能在capturing階段捕捉到事件)。

  1. addEventListener第一個參數是String,事件類型名,沒有前綴on,好比要註冊click事件就傳入「click」,不是「onclick」
  2. 第二個參數是監聽函數,在調用的時候js會傳給他一個Event對象,這個對象放了有關事件的細節,若是調用的這個對象的stopPropagation()方法,則會阻止事件傳播進一步傳播(好比在第一個階段捕捉到事件並運行事件監聽函數,其中調用了event。stopPropagation則事件就不會再被傳播經歷第二第三階段了)
  3. 第三個參數是boolean,true表示事件監聽函數可以在三個階段中的任意一個階段捕捉到事件(符合2級DOM標準),若是是false就表示事件監聽函數不能在capturing階段捕捉到事件(表現同0級DOM)。

2級DOM中監聽函數中的this

經過addEventListener添加的函數中的this,標準中並無規定this必須指向目標元素, 儘管大多數瀏覽器都是這麼實現的,但最終仍是取決於瀏覽器的實現,咱們須要用到目標元素的時候請調用:event.currentTarget.

2級DOM的Event對象

用addEventListener添加的事件監聽函數,在被調用的時候js會傳給他一個Event對象,下面就是這個Event對象的經常使用屬性

  • (1)type:
    發生的事件的類型,例如"click", "mouseover"
    (2)target:
    發生事件的節點,可能與currentTarget不一樣
    (3)currentTarget:
    正在處理事件的節點,若是在capturing階段和冒泡階段處理事件,這個屬性就與target屬性不一樣。在事件監聽函數中應該用這個屬性而不是this
    (4)stopPropagation():
    能夠阻止事件從當前正在處理他的節點傳播
    (5)preventDefault():
    阻止瀏覽器執行與事件相關的默認動做,與0級DOM中返回false同樣
    (6)clientX, clientY:
    鼠標相對於瀏覽器的x座標y座標
    (7)screenX, screenY:
    鼠標相對於顯示器左上角的x座標y座標

IE事件模型

1.Event對象不是傳遞給事件監聽函數,而是經過window對象的event屬性訪問Event對象.
2.IE Event對象經常使用屬性
  • type: 兼容DOM的type屬性
  • srcElement: 兼容DOM的target屬性
  • clientX, clientY: 兼容DOM的clientX, clientY屬性
  • cancelBubble: 布爾值,設爲true同調用stopPropagation()
  • returnValue: 布爾值,設爲false同調用preventDefault()

3. 事件監聽函數註冊
沒有addEventListener,只有attachEvent。2個參數,同addEventListener前兩個,只是事件名帶前綴on。 

IE事件模型沒有capturing階段因此調用attachEvent至關於調用addEvetnListener且第三個參數爲false:

document.getElementById("myTest").attachEvent(" function(){alert(1)});

至關於

document.getElementById("myTest").addEventListener("click", function(){alert(1)}, false);

4. 用attachEvent註冊的函數將被做爲全局函數調用,而不是做爲發生事件的文檔元素的方法,

也就是說this引用的是window對象,而不是事件的目標元素。

事件對象event下的屬性和方法:

由於各個瀏覽器的事件對象不同, 把主要的事件對象的屬性和方法列出來;

(1) bubble : 代表事件是否冒泡

(2) cancelable : 代表是否能夠取消冒泡

(3) currentTarget : 當前事件程序正在處理的元素, 和this同樣的;

(4) defaultPrevented: false ,若是調用了preventDefualt這個就爲真了;

(5) detail: 與事件有關的信息(滾動事件等等)

(6) eventPhase:

  • 若值爲 1 表示處於捕獲階段,
  • 值爲 2 表示處於目標階段,
  • 值爲 3 表示在冒泡階段 target || srcElement: 事件的目標 trusted: 爲ture是瀏覽器生成的,爲false是開發人員建立的(DOM3)

(7) type : 事件的類型

(8) view : 與元素關聯的window, 咱們可能跨iframe;

(9) preventDefault() 取消默認事件;

(10) stopPropagation() 取消冒泡或者捕獲;

(11) stopImmediatePropagation() (DOM3)阻止任何事件的運行;

//stopImmediatePropagation阻止 綁定在事件觸發元素的 其餘同類事件的callback的運行 IE下的事件對象是在window下的,而標準應該做爲一個參數, 傳爲函數第一個參數;

IE的事件對象定義的屬性跟標準的不一樣,如:

  • cancelBubble 默認爲false, 若是爲true就是取消事件冒泡;
  • returnValue 默認是true,若是爲false就取消默認事件;
  • srcElement, 這個指的是target, Firefox下的也是srcElement;

事件監聽 (包括 addEventListener 以及 IE 的 attacheEvent)

舊版本的 IE(IE 9 以前) 在執行 Javascript 時與幾乎全部其它瀏覽器不一樣,在 IE 9 以前的版本中,你須要使用 attachEvent 模塊,就像這樣:

element.attachEvent(' function() { /* do stuff here*/ });複製代碼

在大部分其它瀏覽器(包括 IE 9 以及更新的版本)中,你可使用 addEventListener,就像這樣:

element.addEventListener('click', function() { /* do stuff here*/ }, false);

內聯事件 (Inline Events, 即 HTML 中的onclick=""屬性和element.onclick)

在全部支持 Javascript 的瀏覽器中,你能夠將一個事件監聽內聯,也就是像下面的 HTML 代碼那樣:

內聯事件示例:

<a id="testing" href="#" onclick="alert('did stuff inline');">Click me</a>複製代碼

雖然它的確是能夠完成任務的,並且簡單直接,但絕大部分有經驗的開發者都會盡可能避開使用這樣的方法。

同時,你不能在這裏使用閉包或者匿名函數(雖然處理程序自己就是一個匿名函數),並且你的控制範圍是有限的。
另外一個方法是這樣的

element.onclick = funtion () { /* do stuff here */ }複製代碼

實際上這等價於內聯 Javascript (也就是上面那種在 HTML 標籤屬性中添加的方法),不過這樣能夠擁有更大的控制範圍,同時可使用匿名函數、函數表達式或閉包。

內聯事件有個重大的缺點就是,不像上面提到的事件監聽器那樣,你只能夠指定一個內聯事件。內聯事件會轉化元元素的屬性,那意味着當指定多個的內聯事件時,它以前所指定的內聯事件會被覆蓋掉。

使用上面 HTML 代碼中的 標籤來舉個例子:

var element = document.getElementById('testing');
element.onclick = function () { alert('did stuff #1'); }; 
element.onclick = function () { alert('did stuff #2'); };複製代碼

當你點擊這個元素後,你只能夠看到 "Did stuff #2",緣由是第二個值覆蓋了第一個指定的 onclick 屬性,同時,會把 HTML 中 onclick 屬性也覆蓋掉。

兩種寫法誰更好呢……

主要的問題是瀏覽器兼容性和必要性。你目前是否須要添加一個以上的事件到一個元素上?將來是否須要?大部分時候,你是須要的。因此,使用 attachEvent 和 addEventListener 是很是有必要的,否則用內聯事件就行了。

JQuery 以及不少其它的 Javascript 框架都爲不一樣的瀏覽器封裝了通用的處理 DOM2 事件的通用模型(Models),這樣你能夠在作跨瀏覽器兼容時不須要爲 IE 的歷史遺留問題而煩惱了。一樣的代碼在 jQuery 中作跨瀏覽器兼容,只須要這樣:

$(element).on('click', function () { /* do stuff */ });複製代碼

固然了,不要由於這麼一件事而使用一個框架。你能夠很容易地寫出一個小工具來兼容舊版本的瀏覽器:

function addEvent(element, evnt, funct){
    if (element.attachEvent)
        return element.attachEvent('on' + evnt, funct);
    else
        return elemt.addEventListener(evnt, funct, false);
}

//example
addEvent(
    document.getElementById('myElement'),
    'click',
    function () { aler('hi!'); }
);複製代碼

事件處理程序

一、HTML事件處理程序
某個元素支持的每種事件,均可以使用一個與相應事件處理程序同名的HTML特性來指定。這個特性的值應該是可以執行的JavaScript代碼。

HTML中指定事件處理程序有兩個缺點。一個是時差問題。二個是HTML與JavaScript代碼緊密耦合(若是要更換事件處理程序,就要改動兩個地方:HTML代碼和JavaScript代碼)。

二、DOM0級事件處理程序
要使用JavaScript指定事件處理程序,首先必須取得一個要操做的對象的引用。
每一個元素(包括window和document)都有本身的事件處理程序屬性,這些屬性一般所有小寫,例如onclick。將這種屬性的值設置爲一個函數,就能夠指定事件處理程序:

var btn = document.getElementByIdx_x("myBtn");btn.onclick = function(){ alert("Clicked"); }

使用DOM0級方法指定的事件處理程序被認爲是元素的方法。換句話說,程序中的this引用當前元素。例如:

var btn = document.getElementByIdx_x("myBtn");btn.onclick = function(){ alert("this.id"); }

刪除DOM0級事件處理程序,只需這樣:

btn.onclick = null; //刪除事件處理程序
將事件處理程序設置爲null後,單擊按鈕將不會有任何動做發生。
若是你使用HTML指定事件處理程序,那麼onclick屬性的值就是一個包含着在同名HTML特性中的指定的代碼的函數。而將相應的屬性設置爲null,也能夠刪除以這種方式指定的事件處理函數。

三、DOM2級事件處理程序(IE不支持)
DOM2級事件定義了兩個方法,用於處理指定和刪除事件處理程序的操做:

addEventListener()和removeEventListener()。var btn = document.getElementByIdx_x("myBtn");btn.addEventListener("click",function(){alert("this.id");},false);

使用DOM2級方法添加事件處理程序的主要好處是能夠添加多個事件處理程序。例如:

var btn = document.getElementByIdx_x("myBtn");btn.addEventListener("click",function(){alert("this.id");},false);btn.addEventListener("click",function(){alert("hello world");},false);

刪除事件應用程序。例如:

var btn = document.getElementByIdx_x("myBtn"); var handler = function(){ alert(this.id); }btn.addEventListener("click",handler,false); //省略了其餘代碼btn.removeEventListener("click",handler,false);//有效!

注:匿名函數沒法刪除。


四、IE事件處理程序 

IE實現了與DOM中相似的方法:attachEvent()和detachEvent()

例如:

var btn = document.getElementByIdx_x("myBtn");btn.attachEvent("onclick",function(){alert("this.id");});

注意:attachEvent()的第一個參數是 同理,刪除事件處理函數用detachEvent()函數。

事件類型

一、DOM2級事件類型
(1)UI(user interface,用戶界面)事件,在用戶與頁面上的元素交互時觸發。
(2)鼠標事件,當用戶經過鼠標在頁面上執行操做是觸發。
(3)鍵盤事件,當用戶經過鍵盤在頁面上執行操做是觸發。
(4)HTML事件,當瀏覽器窗口發生變化或發生特定的客戶端/服務器交互時觸發。
(5)變更(mutation)事件,當底層DOM結構發生變化時觸發。
二、UI事件
(1)DOMActive:表示元素已經被用戶操做(經過鼠標或鍵盤)激活。
(2)DOMFocusIn:表示元素已經得到了焦點;
(3)DOMFocousOut:表示元素已經失去了焦點。
支持這幾個UI事件的瀏覽器不多,所以咱們不推薦使用。
三、鼠標事件
(1)鼠標事件觸發順序:
mousedown-》mouseup-》click-》mousedown-》mouseup-》click-》dbclick。
(2)客戶區座標位置
var div = docment.getElementById("myDiv");EventUtil.addHandler(div,"click",function(event){event = EventUtil.getEvent(event);alert("Client coordinates:"+event.clientX+","+event.clientY);});

(3)屏幕座標位置

var div = document.getElementByIdx_x("myDiv");EventUtil.addHandler(div, "click", function(event){event = EventUtil.getEvent(event);alert("Screen coordinates: " + event.screenX + "," + event.screenY);});
});複製代碼

四、鍵盤事件(DOM0級事件支持)(1)鍵盤事件包括三個:keydown 、 keypress 、 keyup。(2)鍵碼,event對象的keyCode屬性中會包含一個代碼,與鍵盤上一個特定的鍵對應。對應的鍵碼請查表。五、HTML事件load、unload、abort、error、select、change、submit、reset、resize、scroll、focus、blur。多數HTML事件都與window對象或表單控件相關。六、變更事件(略)

相關文章
相關標籤/搜索