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

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



javascript中的事件

javascript程序使用的是事件驅動的設計模式,爲一個元素添加事件監聽函數,當這個元素的相應事件被觸發那麼其添加的事件監聽函數就被調用:事件是javascript和HTML交互基礎, 任何文檔或者瀏覽器窗口發生的交互, 都要通過綁定事件進行交互; 

所有瀏覽器都支持DOM0級事件處理程序,且使用該方式時,事件處理程序是在元素的作用域中運行,因此程序中的this都是指向元素。

如何理解DOM0,DOM2,DOM3

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

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

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

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的性質值,

例如:

<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的事件傳播分三個階段進行。

第一,在capturing階段,事件從Document對象沿着文檔樹向下傳播給節點。如果目標的任何一個祖先專門註冊了事件監聽函數,那麼在事件傳播的過程中就會運行這些函數。

第二,階段發生在目標節點自身,直接註冊在目標上的適合的事件監聽函數將運行。

第三,階段是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!'); }
);

事件處理程序

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

另例:

HTML中指定事件處理程序有兩個缺點。一個是時差問題。二個是HTML與JavaScript代碼緊密耦合(如果要更換事件處理程序,就要改動兩個地方:HTML代碼和JavaScript代碼)。
2、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,也可以刪除以這種方式指定的事件處理函數。

3、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);//有效!

注:匿名函數無法刪除。
4、IE事件處理程序 IE實現了與DOM中類似的方法:attachEvent()和detachEvent()

例如:

var btn = document.getElementByIdx_x("myBtn");

btn.attachEvent("onclick",function(){alert("this.id");});

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

事件類型

1、DOM2級事件類型
(1)UI(user interface,用戶界面)事件,在用戶與頁面上的元素交互時觸發。
(2)鼠標事件,當用戶通過鼠標在頁面上執行操作是觸發。
(3)鍵盤事件,當用戶通過鍵盤在頁面上執行操作是觸發。
(4)HTML事件,當瀏覽器窗口發生變化或發生特定的客戶端/服務器交互時觸發。
(5)變動(mutation)事件,當底層DOM結構發生變化時觸發。

2、UI事件
(1)DOMActive:表示元素已經被用戶操作(通過鼠標或鍵盤)激活。
(2)DOMFocusIn:表示元素已經獲得了焦點;
(3)DOMFocousOut:表示元素已經失去了焦點。
支持這幾個UI事件的瀏覽器很少,因此我們不推薦使用。

3、鼠標事件
(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);
});

4、鍵盤事件(DOM0級事件支持)
(1)鍵盤事件包括三個:keydown 、 keypress 、 keyup。
(2)鍵碼,event對象的keyCode屬性中會包含一個代碼,與鍵盤上一個特定的鍵對應。
對應的鍵碼請查表。

5、HTML事件
load、unload、abort、error、select、change、submit、reset、resize、scroll、focus、blur。
多數HTML事件都與window對象或表單控件相關。

6、變動事件(略)



參考資料:

http://segmentfault.com/q/1010000000766310/a-1020000000777355

http://blog.sina.com.cn/s/blog_825442790101354v.html

http://www.csdn123.com/html/topnews201408/5/11405.htm

http://blog.csdn.net/sixwinds/article/details/5656413

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