javascript中有兩種事件模型:DOM0,DOM2。而對於這兩種的時間模型,我一直不是很是的清楚,如今經過網上查閱資料終於明白了一些。javascript
一. DOM0級事件模型html
DOM0級事件模型是早期的事件模型,全部的瀏覽器都是支持的,並且其實現也是比較簡單。代碼以下:java
<p id = 'click'>click me</p>
<script>
document.getElementById('click').onclick = function(event){
alert(event.target);
}
</script>
這種事件模型就是直接在dom對象上註冊事件名稱,這段代碼就是在p標籤上註冊了一個onclick事件,在這個事件函數內部輸出點擊的目標。而解除事件則更加簡單,就是將null複製給事件函數,以下:瀏覽器
document.getElementById('click'_).onclick = null;
由此咱們能夠知道dom0中,一個dom對象只能註冊一個同類型的函數,由於註冊多個同類型的函數的話,就會發生覆蓋,以前註冊的函數就會無效。dom
var click = document.getElementById('click');
click.onclick = function(){
alert('you click the first function');
};
click.onclick = function(){
alert('you click the second function')
}
在這段代碼中,咱們爲dom對象註冊了兩個onclick函數,可是結果是隻執行了第二個註冊的函數,前面所註冊的函數被覆蓋了。函數
二. DOM2級事件模型post
1. 事件捕獲和事件冒泡(capture,bubble)ui
首先,IE8及如下是不支持這種事件模型的。事件捕獲和事件冒泡的機制以下圖:this

如上圖所示,123表明事件捕獲,4567表明事件冒泡。首先咱們使用下面的代碼:lua
<div id = 'outer' style = 'margin: 100px 0 0 100px; width: 200px;height: 200px; background: red;'>
<div id="inner" style = 'margin-left:20px; width: 50px;height:50px; background: green;'></div>
</div>
假設咱們點擊了ID爲inner的div,那麼此時的事件流程就是,首先執行捕獲階段:document-html-body-div(outer)。而後執行冒泡階段:div(inner)-div(outer)-body-html-document。
2. DOM2級的註冊事件和解除事件
在DOM2級中使用addEventListener和removeEventListener來註冊和解除事件(IE8及以前版本不支持)。這種函數較之以前的方法好處是一個dom對象能夠註冊多個相同類型的事件,不會發生事件的覆蓋,會依次的執行各個事件函數。
addEventListener('事件名稱','事件回調','捕獲/冒泡')。示例以下:
<div id = 'outer' style = 'margin: 100px 0 0 100px; width: 200px;height: 200px; background: red;'>
<div id="inner" style = 'margin-left:20px; width: 50px;height:50px; background: green;'></div>
</div>
<script>
var click = document.getElementById('inner');
click.addEventListener('click',function(){
alert('click one');
},false);
click.addEventListener('click',function(){
alert('click two');
},false);
</script>
首先咱們要知道addEventListenr的第一個參數是事件名稱,與DOM0級不一樣的是沒有」on「,另外第三個參數表明捕獲仍是冒泡,true表明捕獲事件,false表明冒泡事件。
而在這段代碼中,咱們爲inner的div註冊了兩個click事件函數,結果是瀏覽器會依次執行這兩個函數。
下面咱們演示如何使用事件流的發生機制。
<div id = 'outer' style = 'margin: 100px 0 0 100px; width: 200px;height: 200px; background: red;'>
<div id="inner" style = 'margin-left:20px; width: 50px;height:50px; background: green;'></div>
</div>
<script>
var click = document.getElementById('inner');
var clickouter = document.getElementById('outer');
click.addEventListener('click',function(){
alert('inner show');
},true);
clickouter.addEventListener('click',function(){
alert('outer show');
},true);
</script>
這段代碼,咱們使用了捕獲事件,因爲inner是嵌套在outer中的,因此咱們知道當使用捕獲的時候outer是應該首先捕獲到這個事件的,其次inner才能捕獲到這個事件。那麼結果就是outer首先執行,其次是inner執行。
那麼我把outer的執行時機改成冒泡的階段呢?
alickouter.addEventListener('click',function(){
alert('outer show');
},false);
這種狀況下,就是先執行inner後執行outer了。同理咱們把兩者的事件執行時機都改成冒泡階段的話,依舊是先執行inner後執行outer。那麼還有個問題,就是若是咱們把inner註冊兩個click事件,一個是在捕獲階段,另外一個是在冒泡階段,也就是說把addEventListenter的第三個參數分別設置爲false和true,那麼執行的順序又是怎樣的呢。
<script>
var click = document.getElementById('inner');
var clickouter = document.getElementById('outer');
click.addEventListener('click',function(){
alert('capture show');
},true);
click.addEventListener('click',function(){
alert('bubble show');
},false);
</script>
這種狀況下首先這些的是capture show,其次是bubble show。可是這種結果是與註冊的順序有關係的,先註冊就先執行。由於咱們在看事件捕獲和事件冒泡示意圖,發現最後具體的dom對象是隻有一個的。
那麼 若是咱們給outer和inner都註冊了click事件可是我不但願outer執行怎麼辦呢?這個時候咱們就須要用到stopPropagation函數了,這個函數是用來阻止冒泡,言下之意是讓事件再也不繼續冒泡下去,這樣接下來註冊一樣類型事件的dom對象就不會執行了。好比在自制下拉框的時候,咱們點擊瀏覽器的其餘位置,咱們須要下拉框的options隱藏,這時咱們就要用到stopPropagation了。以下:
<script>
var click = document.getElementById('inner');
var clickouter = document.getElementById('outer');
click.addEventListener('click',function(event){
alert('inner show');
event.stopPropagation();
},false);
clickouter.addEventListener('click',function(){
alert('outer show');
},false);
</script>
正常的狀況下,咱們在不添加stopPropagation函數時,首先應該執行inner,而後執行outer,可是當咱們在inner的事件函數中添加了stopPropagation函數以後,執行完inner的事件函數以後,就不會在執行outer的事件函數了,也能夠理解爲事件冒泡到inner以後就消失了,所以也就不會在執行接下來的事件函數了。
因爲事件捕獲階段沒有能夠阻止事件的函數,因此通常都是設置爲事件冒泡。
Javascript與HTML之間的交互是經過事件實現的。
事件,就是文檔或瀏覽器窗口中發生的一些特定的交互瞬間。
可使用偵聽器來預約事件,以便事件發生時執行相應代碼。
事件流
事件流描述的是從頁面中接受事件的順序。
事件冒泡
IE的事件流叫作事件冒泡,即事件開始是由最具體的元素接收,而後逐級向上傳播到較爲不具體的節點(文檔)。
若是點擊了頁面中的一個div元素,那麼這個click事件可能會按照以下順序傳播:
- < div>
- < body>
- < html>
- document
也就是說,click事件首先在div元素上發生,而後click事件沿DOM樹向上傳播,在每一級節點上都會發生,直至傳播至document對象。

全部現代瀏覽器都支持冒泡事件。
事件捕獲
Netscape團隊提出的另外一種事件流叫作事件捕獲。事件捕獲的思想是不太具體的節點應該更早接收到事件,最具體的節點應該最後接收到事件。
事件捕獲的用意在於事件到達預約目標以前捕獲它。
這時,單擊div元素就會如下列順序觸發click事件:
- document
- < html>
- < body>
- < div>
事件捕獲過程當中,document對象首先接受click事件,而後事件沿DOM樹依次向下,一直傳播到事件的實際目標,即div元素。

雖然大多數瀏覽器都支持事件捕獲,但不多有人使用。
DOM事件流
DOM2級事件規定的事件流包括三個階段:事件捕獲階段、處於目標階段、事件冒泡階段。
- 首先發生的是事件捕獲,爲截獲事件提供了機會。
- 而後是實際的目標接收到事件。
- 而後冒泡階段發生,事件又傳播迴文檔。

在DOM事件流中,實際的目標在捕獲階段不會接受到事件。這意味着在捕獲階段,事件從document到< html>再到< body>後就中止了。
下一個階段是「處於目標」階段,因而事件在div元素上發生,並在事件處理中被當作冒泡階段的一部分。
即便DOM2級事件明確要求捕獲階段不會涉及事件目標,但大多數瀏覽器都會在捕獲階段觸發事件對象上的事件,結果就是有兩個機會在目標對象上面操做事件。
事件處理程序
響應某個事件的函數就叫作事件處理程序(或事件偵聽器)。
事件處理程序的名字以「on」開頭,所以click事件的事件處理程序就是onclick,load事件的事件處理程序就是onload。
爲事件指定處理程序的方式有好幾種。
HTML事件處理程序
某個元素支持的每種事件,均可以使用一個與相應事件處理程序同名的HTML特性來指定。這個特性的值應該是可以執行的javascript代碼。
<input type="button" value="click me" onclick="alert('clicked')"/>
當單擊這個按鈕時,就會顯示一個警告框。這個操做是經過指定onclick特性並將一些javascript代碼做爲它的值來定義的。因爲這個值是javascript,所以不能在其中使用未經轉義的HTML語法字符。
在HTML中定義的事件處理程序能夠包含要執行的具體動做,也能夠調用在頁面其餘地方定義的腳本。
<script type="text/javascript"> function showMessage(){ alert("hello world") } </script>
<input type="button" value="click me" onclick="showMessage()" />
在這個例子中,單擊按鈕就會調用showMessage函數。這個函數是在一個獨立的< script>元素中定義的,固然也能夠被包含在一個外部文件中。事件處理程序中的代碼在執行時,有權訪問全局做用域中的任何代碼。
這樣指定事件處理程序具備一些獨到之處。
首先,這樣會建立一個封裝着元素屬性值的函數。
這個函數中有一個局部變量event,也就是事件對象。
<input type="button" value="click me" onclick="alert(event.type)" />
經過event變量,能夠直接訪問事件對象。
在這個函數內部,this值等於事件的目標元素。
<input type="button" value="click me" onclick="alert(this.value)" />
關於這個動態建立的函數,另外一個有意思的地方就是它擴展做用域的方式。這個函數使用with像下面這樣擴展做用域:
function(){
with(document){
with(this){
}
}
}
如此一來,事件處理程序能夠直接訪問本身的屬性:
<input type="button" value="click me" onclick="alert(value)" />
若是當前元素是一個表單輸入元素,則做用域中還會包含訪問表單元素的入口。
function(){
with(document){
with(this.form){
with(this){
}
}
}
}
這樣的擴展方式,無非就是想讓事件處理程序無需引用表單元素就能訪問其餘表單字段。
<form method="post">
<input type="text" name="username" value="">
<input type="button" value="echo username" onclick="alert(username.value)">
</form>
注意,這個例子中直接引用了username元素。
可是,在HTML中指定事件處理程序有兩個缺點:
-
存在一個時差問題。用戶可能在HTML元素一出如今頁面上就觸發相應的事件,但當時的事件處理程序有可能尚不具有執行條件。
之前面的例子來講明,假設showMessage函數是在按鈕下方,頁面的最底部定義的。若是用戶在頁面解析showMessage( )以前就單擊了按鈕,就會引起錯誤。爲此,不少HTML事件處理程序都會被封裝到一個try-catch塊中,一遍錯誤不會浮出水面。
-
這樣擴展事件處理程序的做用域鏈在不一樣瀏覽器中會致使不一樣結果。
- HTML代碼與javascript代碼緊密耦合。若是要更換事件處理程序,就要改動兩個地方:HTML代碼和javascript代碼。這正是你們摒棄HTML事件處理程序,轉而使用javascript指定事件處理程序的緣由所在。
DOM0級事件處理程序
經過javascript指定事件處理程序的傳統方式,就是將一個函數賦值給一個事件處理程序屬性。
每一個元素(包括window和document)都有本身的事件處理程序屬性,這些屬性一般所有小寫,例如onclick。將這種屬性的值設置爲一個函數,就能夠指定事件處理程序:
var btn = document.getElementById("myBtn");
btn.onclick = function(){
alert("clicked");
}
在此,咱們經過文檔對象取得了一個按鈕的引用,而後爲它指定了onclick事件處理程序。
但要注意,在這些代碼運行之前不會指定事件處理程序,所以若是這些代碼在頁面中位於按鈕後面,就有可能在一段時間內怎麼單擊都沒有反應。
使用DOM0級方法指定的事件處理程序被認爲是元素的方法。所以,這時候的事件處理程序是在元素的做用域中運行;換句話說,程序中的this引用當前元素。
var btn = document.getElementById("myBtn");
btn.onclick = function(){
alert(this.id);
}
不只僅是id,實際上能夠在事件處理程序中經過this訪問元素的任何屬性和方法。
以這種方式添加的事件處理程序會在事件流的冒泡階段被處理。
也能夠刪除經過DOM0級方法指定的事件處理程序,只要像下面這樣將事件處理程序屬性的值設置爲null便可:
btn.onclick = null;
將事件處理程序設置爲null後,再單擊按鈕將不會有任何動做發生。
若是使用HTML指定事件處理程序,那麼onclick屬性的值就是一個包含着在同名HTML特性中指定的代碼的函數。將相應的屬性設爲null,也能夠刪除以這種方式指定的事件處理程序。
DOM2級事件處理程序
DOM2級事件定義了2個方法:
- addEventListener()
- removeEventListener()
全部DOM節點中都包含這兩個方法,而且它們都接受3個參數:
- 要處理的事件名
- 做爲事件處理程序的函數
- 一個布爾值
- true:表示在捕獲階段調用事件處理程序
- false:表示在冒泡階段調用事件處理程序
要在按鈕上爲click事件添加事件處理程序,可使用下列代碼:
var btn = document.getElementById("myBtn");
btn.addEventListener("click",function(){
alert(this.id);
},false);
上面的代碼爲一個按鈕添加了onclick事件處理程序,並且該事件會在冒泡階段被觸發。
與DOM0級方法同樣,這裏添加的事件處理程序也是在其依附的元素的做用域中運行,所以this表明該元素。
使用DOM2級方法添加事件處理程序的主要好處是能夠添加多個事件處理程序。
btn.addEventListener("click",function(){
alert(this.id);
},false);
btn.addEventListener("click",function(){
alert("hello world");
},false);
這裏爲按鈕添加了兩個事件處理程序,這兩個事件處理程序會按照添加他們的順序觸發,所以首先會顯示元素的ID,其次會顯示「hello world」消息。
經過addEventListener()添加的事件處理程序只能使用removeEventListener()來移除;移除時傳入的參數與添加處理程序時使用的參數相同。這也意味着經過addEventListener()添加的匿名函數將沒法移除。
btn.addEventListener("click",function(){
alert(this.id);
},false);
btn.removeEventListener("click",function(){
alert(this.id);
},false);
這個例子中,在移除事件處理程序時,看似使用了相同的參數,但實際上第二個參數與傳入addEventListener()中的是徹底不一樣的函數。
傳入removeEventListener()中的事件處理程序函數必須與傳入addEventListener()中的徹底相同。
var handler = function(){
alert(this.id);
}
btn.addEventListener("click",handler false);
btn.removeEventListener("click",handler ,false);
重寫後的這個列子能夠奏效,由於在addEventListener()和removeEventListener()中使用了相同的函數。
大多數狀況下,都是將事件處理程序添加到事件流的冒泡階段,這樣能夠最大限度的兼容各類瀏覽器。最好只在須要在事件到達目標以前截獲他的時候將事件處理程序添加到捕獲階段。若是不是特別須要,不建議在事件捕獲階段註冊時間處理程序。
IE事件處理程序
IE實現了與DOM中相似的鏈各個方法:attachEvent()和detachEvent()。
這兩個方法接受相同的兩個參數,事件處理程序名稱與事件處理程序函數。
因爲IE8及更早版本只支持事件冒泡,因此經過attachEvent()添加的事件處理程序都會被添加到冒泡階段。
要使用attachEvent()爲按鈕添加一個事件處理程序,可使用如下代碼:
btn.attachEvent("onclick",function(){
alert("hello world");
});
注意,attachEvent()的第一個參數是「onclick」,而非DOM方法中的「click」。
在IE中使用attachEvent()與使用DOM0級方法的主要區別在於事件處理程序的做用域。在使用DOM0級方法的狀況下,事件處理程序會在其所屬元素的做用域內運行。在使用attachEvent()方法的狀況下,事件處理程序會在全局做用域中運行,所以this等於window。
btn.attachEvent("onclick",function(){
alert(this == window);
});
與addEventListener()相似,attachEvent()方法也能夠用來爲一個元素添加多個事件處理程序。
btn.attachEvent("onclick",function(){
alert("clicked");
});
btn.attachEvent("onclick",function(){
alert("hello world");
});
使用attachEvent爲同一個按鈕添加了兩個不一樣的事件處理程序。但與DOM事件不一樣的是,這些事件處理程序不是以添加他們的順序執行,而是以相反的順序被觸發。 單擊這個按鈕,首先會看到「hello world」,而後纔是「clicked」。
使用attachEvent()添加的事件能夠經過detachEvent()來移除,條件是必須提供相同的參數。這也意味着添加的匿名函數將不能被移除。不過,只要可以將對相同函數的引用傳給detachEvent(),就能夠移除相應的事件處理程序。
var handler = function(){
alert(this.id);
}
btn.attachEvent("onclick",handler );
btn.detachEvent("onclick",handler );
這個例子將保存在變量handler中的函數做爲事件處理程序。所以,後面的detachEvent()可使用相同的函數來移除事件處理程序。
支持IE事件處理程序的瀏覽器有IE和opera。
跨瀏覽器的事件處理程序
能夠本身編寫跨瀏覽器的事件處理程序,只要在適當的地方使用能力檢測便可。要保證處理事件的代碼能在大多數瀏覽器下一致地運行,只需關心冒泡階段。
第一個要建立的方法是addHandler(),他的職責是視狀況分別使用DOM0級方法、DOM2級方法或IE方法來添加事件。這個方法屬於一個名叫EventUtil的對象,咱們將使用這個對象來處理瀏覽器間的差別。
addHandler接收3個參數:要操做的元素、事件名稱和事件處理函數。
與addHandler()對應的方法是removeHandler(),它也接受相同的參數。這個方法的職責是移除以前添加的事件處理程序——不管該事件處理程序是採起什麼方式添加到元素中的,若是其它方法無效,默認採用DOM0級方法。
var EventUtil = {
addHandler:function(element,type,handler){
if(element.addEventListener){
element.addEventListner(type,handler,false);
}else if(element.attachEvent){
element.attachEvent("on"+type,handler);
}else{
element["on"+type] = handler;
}
},
removeHandler:function(element,type,handler){
if(element.removeEventListener){
element.removeEventListner(type,handler,false);
}else if(element.detachEvent){
element.detachEvent("on"+type,handler);
}else{
element["on"+type] = null;
}
}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
這兩個方法首先都會檢測傳入的元素中是否存在DOM2級方法。若是存在DOM2級方法,則使用該方法;若是存在的是IE的方法,則採起第二種方案。最後一種可能就是DOM0級方法,此時咱們使用的是方括號語法來將屬性名指定爲事件處理程序,或者將屬性設置爲null。
能夠像下面這樣使用EventUtil對象:
var btn = document.getElementById("myBtn");
var handler = function(){
alert(this.id);
}
EventUtil.addHandler(btn,"click",handler);
EventUtil.removeHandler(btn,"click",handler);
addHandler()和removeHandler()沒有考慮到全部的瀏覽器問題,例如IE中的做用域問題。不過,使用它們添加和移除事件處理程序仍是足夠了。
此外還要注意,DOM0級對每一個事件只支持一個事件處理程序。
事件對象
在觸發DOM上的某個事件時,會產生一個事件對象event,這個對象中包含着全部與事件有關的信息。包括致使事件的元素、事件的類型以及其餘與特定事件相關的信息。
全部瀏覽器都支持event對象,但支持方式不一樣。
DOM中的事件對象
兼容DOM的瀏覽器會將一個event對象傳入到事件處理程序中。不管指定事件處理程序時使用什麼方法(DOM0級或DOM2級),都會傳入event對象。
btn.onclick = function(event){
alert(event.type); //"click"
}
btn.addEventListener("click",function(event){
alert(event.type); //"click"
},false);
這個例子中的兩個事件處理程序都會彈出一個警告框,顯示由event.type屬性表示的事件類型。這個屬性始終都會包含被觸發的事件類型。(與傳入addEventListener()和removeEventListener()的事件類型一致)。
在經過HTML特性指定事件處理程序時,變量event中保存着event對象。
<input type="button" value="click me" onclick="alert(event.type)" />
以這種方式提供event對象,可讓HTML特性事件處理程序與javascript函數執行相同的操做。
event對象包含與建立它的特定事件有關的屬性和方法。觸發的事件類型不同,可用的屬性和方法也不同。
currentTarget、target
target在事件流的目標階段;currentTarget在事件流的捕獲,目標及冒泡階段。只有當事件流處在目標階段的時候,兩個的指向纔是同樣的, 而當處於捕獲和冒泡階段的時候,target指向被單擊的對象而currentTarget指向當前事件活動的對象(通常爲父級)。
換句話說,event.target指向引發觸發事件的元素,而event.currentTarget則是事件綁定的元素
在事件處理程序內部,對象this始終等於currentTarget的值,而target只包含事件的實際目標。若是直接將事件處理程序指定給了目標元素,則this、currentTarget、target包含相同的值。
btn.onclick = function(event){
alert(event.currentTarget === this);
alert(event.target === this);
}
因爲click事件的目標是按鈕,所以這三個值是相等的。
若是事件處理程序存在於按鈕的父節點中,那麼這些值是不相同的:
document.body.onclick = function(event){
alert(event.currentTarget === document.body);
alert(this === document.body);
alert(event.target === document.getElementById("myBtn"));
}
當單擊這個例子中的按鈕時,this和currentTarget都等於document.body,由於事件處理程序是註冊到這個元素上的。然而target元素卻等於按鈕元素,由於它是click的真正目標。因爲按鈕上沒有註冊事件處理程序,結果click事件就冒泡到了document.body上了,在那裏事件才獲得了處理。
type
在須要經過一個函數處理多個事件時,可使用type屬性。
var handler = function(event){
switch(event.type){
case "click":
alert("clicked");
break;
case "mouseover":
event.target.style,backgroundColor = "red";
break;
case "mouseout":
event.target.style.backgroundColor = "";
break;
}
};
btn.onclick = handler;
btn.onmouseover = handler;
btn.onmouseout = handler;
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
這個例子定義了一個名爲handler的函數,用於處理3種事件:click、mouseover、mouseout。函數中經過檢測event.type屬性,讓函數可以肯定發生了什麼事件,並執行相應的操做。
preventDefault()
要阻止特定事件的默認行爲,可使用這個方法。例如,連接的默認行爲是被單擊時會導航到其href特性指定的URL。若是想阻止這一默認行爲,那麼經過鏈接的onclick事件處理程序能夠取消它。
link.onclick = function(event){
event.preventDefault();
}
只有cancelable屬性設爲true的事件,纔可使用preventDefault()來取消其默認行爲。
stopPropagation()
用於當即中止事件在DOM層次中的傳播,即取消進一步的事件捕獲或冒泡。
例如,直接添加到一個按鈕的事件處理程序能夠調用stopPropagation(),從而避免觸發註冊在document.body上面的事件處理程序。
btn.onclick = function(event){
alert("clicked");
event.stopPropagation();
}
document.body.onclick = function(event){
alert("body clicked");
}
對於這個例子而言,若是不調用stopPropagation(),就會在單擊按鈕時出現兩個警告框。使用了以後,因爲click事件根本不會被傳播到document.body,所以就不會觸發註冊在document.body上的onclick事件程序。
eventPhase
這個屬性能夠用來肯定事件當前正位於事件流的哪一個階段。
- 捕獲階段:eventPhase = 1;
- 處於目標對象上:eventPhase = 2;
- 冒泡階段:eventPhase = 3;
要注意的是,儘管「處於目標」發生在冒泡階段,可是eventPhase仍等於2.
btn.onclick = function(event){
alert(event.eventPhase);
}
document.body.addEventListener("click",function(event){
alert(event.eventPhase);
},true);
document.body.onclick = function(event){
alert(event.eventPhase);
}
當單擊這個例子中的按鈕時:
- 首先執行的事件處理程序是在捕獲階段觸發的添加到document.body中的那一個,會彈出一個警告框顯示1
- 其次會觸發在按鈕上註冊的事件處理程序,此時eventPhase爲2
- 最後在冒泡階段觸發添加到document.body中的那一個,顯示eventPhase爲3。
當eventPhase等於2時,this、target、currentTarget始終都是相等的。
只有在事件處理程序執行期間,event對象纔會存在;一旦事件處理程序執行完成,event對象就會被銷燬。
IE中的事件對象
與訪問DOM中的event對象不一樣,要訪問IE中的event對象有幾種不一樣的方式,取決於指定事件處理程序的方法。
- 在使用DOM0級方法添加事件處理程序時,event對象做爲window隨想的一個屬性存在:
btn.onclick = function(){
var event = window.event;
alert(event.type);
}
- 若是事件處理程序是經過attachEvent()添加的,那麼就會有一個event對象做爲參數被傳入事件處理程序函數中:
btn.attachEvent("onclick",function(event){
alert(event.type); //"click"
})
在這種狀況下,也能夠經過window對象來訪問event對象,就像使用DOM0級方法同樣。不過爲了方便起見,同一個對象也會做爲參數傳遞。
- 若是是經過HTML特性指定的事件處理程序,那麼還能夠經過一個名爲event的變量來訪問event對象(與DOM中的事件模型相同)。
<input type="button" value="click me" onclick="alert(event.type)"/>
IE的event對象一樣也包含與建立它的事件相關的屬性和方法。其中不少屬性和方法都有對應的或者相關的DOM屬性和方法。
srcElement
事件的目標,與DOM中的target屬性相同。
由於事件處理程序的做用域是根據指定它的方式來肯定的,因此不能認爲this會始終等於事件目標,所以最好仍是使用event.srcElement比較保險。
btn.onclick = function(){
alert(window.event.srcElement == this);
}
btn.attachEvent("onclick",function(event){
alert(event.srcElement == this);
})
第一個使用DOM0級方法指定的事件處理程序,srcElement屬性等於this。
但在第二個事件處理程序中,因爲this指向window,所以這二者的值不相同。
returnValue
默認值爲true,將其設置爲false就能夠取消事件的默認行爲,與DOM中的preventDefault()做用相同。
link.onclick = function(){
window.event.returnValue = false;
}
cancelBubble
與DOM中的stopPropagation()相同,都是用來中止事件冒泡的。因爲IE不支持事件捕獲,所以只能取消事件冒泡。但stopPropagation()能夠同時取消捕獲和冒泡。
btn.onclick = function(){
alert("clicked");
window.event.cancelBubble = true;
}
document.body.onclick = function(){
alert("body clicked");
}
經過在onclick事件處理程序中將cancelBubble設置爲true,就能夠阻止時間經過冒泡而觸發document.body中註冊的事件處理程序。結果就是,單擊按鈕以後,只顯示一個警告框。
跨瀏覽器的事件對象
雖然DOM和IE中的event對象不一樣,但基於它們之間的類似性依舊能夠拿出跨瀏覽器的方案來。
能夠對前面的EventUtil對象加以加強:
var EventUtil = {
getEvent:function(event){
return event?event:window.event;
},
getTarget:function(event){
return event.target||event.srcElement;
},
preventDefault:function(event){
if(event.preventDefault){
event.preventDefault();
}else{
event.returnValue = false;
}
},
stopPropagation:function(event){
if(event.stopPropagation){
event.stopPropagation();
}else{
event.cancelBubble = true;
}
}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
能夠像下面這樣使用:
btn.onclick = function(event){
event = EventUtil.getEvent();
var target = EventUtil.getTarget(event);
EventUtil.preventDefault(event);
EventUtil.stopPropagation(event);
}
別忘了因爲IE不支持事件捕獲,所以stopPropagation在跨瀏覽器的狀況下,只能用來阻止事件冒泡。