事件就是用戶或者瀏覽器自身執行的某種動作。諸如click、load、和scroll等等,都是事件的名字。而響應某個事件的函就叫做事件處理程序(或事件偵聽器)。事件處理程序的名字都是以”on“開頭,因此ckick事件的事件處理程序就是onclick,load的事件處理程序就是onload。 頁面中添加事件的有幾種方式- 直接將代碼寫在HTMl上
<div onclick="alert('Hello World');">Nowamagic</div> 代碼少的還勉強可以,代碼多的話就哭了寫頁面的哥們了。 - 定義一個函數,分配給html元素
<script type="text/javascript"> function clk(){} </script> //..... <div onclick="clk()">Div2 Element</div> 這樣做雖然能減少html代碼上的js量,但是這樣子做有幾個缺點:用戶可能在HTMl代碼已經出現在頁面上,但是js事件函數可能還沒加載進來的情況下就點擊了事件對象元素,從而導致錯誤;還有就是HTML與javascript代碼還是未分離完全,如果要修改就要改HTML代碼和javascript代碼兩處 - HTML與javascript代碼完全分離
document.getElementById('myButton').onclick = function(){ alert('Hello!'); } <div id="myButton">點擊按鈕/div> 它只需要HTML元素提供一個id屬性(或其它能獲取該元素對象的方式),就可以實現事件的注冊。真正做到HTML與javascript代碼完全分離,結構與行為完全分離的事件處理方法。
如何監聽事件DOM Leavl 0DOM Leavl 0是最早的事件處理形式,它既可以直接寫在HTMl上,也可以把一個函數分配給一個事件處理程序。然而,這種方式給一個元素的同一事件只允許一個處理器。因此,我們還要繼續完善。 W3C DOM Leavl 2 – 事件監聽器通過W3C DEMO Leavl 2事件處理,我們不會直接把一個函數分配給一個事件處理程序;相反,我們將新函數添加一個事件監聽器: var el = document.getElementById('myButton') el.addEventListener( 'click', function(){ alert('Hello!'); }, false) targetElement.addEventlistener(typeOfEvent,listenerFunction,useCapture); W3C DOM Leaval 2通用語法盡管這個方法看起來比之前那個方法復雜了一點,但是那些額外的代碼還是有必要打出來的。對于DOM級別2的事件最大的好處就是一個事件可以注冊許多處理器。 addEventlistener的頭兩個參數是目標對象和事件,不僅如此,函數最后一個參數,可以指定處理器是在捕獲階段還是冒泡階段被觸發(通過設置”addEventListener()”函數的第三個參數來指定 – true表示在捕獲階段,false表示在冒泡階段) 接下來將針對W3C DOM Leavl 2事件進行討論。 事件在文檔中被傳遞的兩種模型W3C DOM Leavl 2事件流包括三個階段:事件捕獲階段、處于目標簡短和事件冒泡階段。 首先我們了解下事件冒泡和事件捕獲。 事件冒泡在頁面上有多個事件,也可以多個元素響應同一個事件。假設網頁上有兩個元素,其中一個元素嵌套在另一個元素中,并且都被綁定了 click 事件,同時 body 也綁定了 click 事件,如下: js代碼如下: window.onload = function(){ var oBubble = document.getElementById("oBubble"); var oBubble1 = document.getElementById("oBubble1"); var oBubble2 = document.getElementById("oBubble2"); oBubble.onclick = function(){ alert("Bubble") } oBubble1.onclick = function(){ alert("Bubble1") } oBubble2.onclick = function(){ alert("Bubble2") } }
html代碼如下: <body id="oBubble">//點擊#oBubble彈出Bubble <div id="oBubble1">//點擊#oBubble1先后彈出Bubble1、Bubble <span id="oBubble2">oBubble</span>//點擊#oBubble2先后彈出Bubble2 、Bubble1、Bubble </div> </body> 事件順序:span→div→body,如下圖所示:  事件冒泡實例圖例
很明顯,每個元素都會按照(inside→outside)的冒泡型事件,所以事件冒泡會引起預料之外的效果。事件冒泡是IE-DOM處理事件對象的方法。 事件捕獲事件捕獲和事件冒泡是剛好相反的兩個過程,事件捕獲是按照(outside→inside)的冒泡型事件開始觸發。因此拿以上冒泡例子,alert信息是跟事件冒泡完全相反的順序。 一些注意事項: - W3C DOM Leavl 2標準的addEventListener方法執行事件的順序是按照事件注冊的順序執行的。而IE的attachEvent方法則相反–后注冊的事件先觖發,先注冊的事件后觸發。
- W3C DOM Leavl 2標準的瀏覽器文本節點也會冒泡,而IE內核的瀏覽器文本節點不會冒泡。
- W3C DOM Leavl 2瀏覽器事件對象與IE內核的瀏覽器事件不同(具體請參閱)。
- DOM標準的瀏覽器事件卸載方式與IE內核的事件卸載方式不同。
接下來我們就來解決跨瀏覽器的事件處理的方案。 跨瀏覽器的事件處理函數前面我們介紹了事件冒泡和事件捕獲兩種事件事件獲取方式,而W3C模型 是兩者中和。就是事件發生時,先從頂層開始進行事件捕獲,直到事件觸發到達了事件源元素。然后,再從事件源往上進行事件冒泡,直到到達document。 利用W3C DOM Leavl 2事件監聽器,就是 addEventListener函數。我們可以自己選擇綁定事件時采用事件捕獲還是事件冒泡,方法就是綁定事件時通過addEventListener函數,上面我們介紹過它的三個參數了:如果第三個參數若是true,則表示采用事件捕獲,若是false,則表示采用事件冒泡。 但是在一個支持W3C DOM的瀏覽器中,按照DOM Leavl 1綁定事件方式,采用的全都是事件冒泡方式。大多數時候,我們也是希望事件從內部嵌套的的元素冒泡到外圍元素。 解決方案以上我們介紹過 W3C DOM Leaval 2事件綁定中的addEventlistener,可以為元素添加多個事件,而且最后一個參數還支持事件冒泡或捕獲,IE6/7/8仍然沒有遵循標準而使用了自己專有的attachEvent,且不支持事件捕獲,所有事件都是發生在冒泡階段。 所以創建一個可重用。實現了DOM Leavl 2事件處理的事件處理函數,但是,它還是要跨瀏覽器。如下經典代碼 listenEvent函數代碼 function listenEvent(eventTarget, eventType, evrntHandler) { if (eventTarget.addEventListener){ eventTarget.addEventListener(eventType, evrntHandler, true);//IE9等其他現代瀏覽器 } else if (eventTarget.attachEvent){ eventType = "on"+eventType; eventTarget.attachEvent(eventType,evrntHandler) //IE6、7、8 } else {eventTarget["on" + eventType] = evrntHandler;}//IE5~ 個人覺得不寫也罷。 } listenEvent函數使用 listenEvent(document,"click",processClick) 可重用的事件處理函數此處理函數接受3個函數:目標對象、事件(作為一個字符串),以及函數名稱。首先測試對象,看看它是否支持addEventListener(W3C DOM Leaval 2的事件監聽方法),如果支持這個方法,就把事件映射到事件處理函數。回到代碼,因為IE6、7、8不支持addEventListener,所以檢查是否支持attachEvent,記得前面加”on“,因為不加”on“只是事件的名字,但是因為IE6、7、8只支持向上冒泡,所以此方案中 addEventListener的第三個參數是false。最后為了兼容DOM leaval 0事件處理,還要加最后一行代碼。 使用W3C DOM Leavl 2處理事件事件監聽不會有覆蓋之前綁定事件的現象,每個綁定的事件都會被執行,不過 attachEvent 為元素增加的一系列事件不是以添加它們順序執行的,而是以相反的順序觸發。最重要的是,采用事件監聽給對象綁定方法后,可以解除相應的綁定。跟以上代碼類似,removeEventListener跟addEventListener對應,detachEvent跟eventType對應,得到如下解決方案: stopListening函數代碼 function stopListening(eventTarget, eventType, evrntHandler) { if (eventTarget.removeEventListener){ eventTarget.removeEventListener(eventType, evrntHandler, true);//IE9等其他現代瀏覽器 } else if (eventTarget.attachEvent){ detachEvent = "on"+eventType; eventTarget.detachEvent(eventType,evrntHandler) //IE6、7、8 } else {eventTarget["on" + eventType] = null;}//IE5~ } stopListening(document,"click",processClick) 可重用的事件處理函數在DOM標準的事件卸載方式中需要注意的是:事件捕獲的參數。如果你的事件是注冊在捕獲階段,則卸載事件時,必須將其指定為捕獲階段(true),否則無法卸載;如果你的事件注冊在注冊在冒泡階段,則必須將其指定為冒泡階段(false),否則同樣無法卸載。 現在,如果我們想停止監聽一個事件,可以直接調用stopListening,同樣傳入3個參數:目標對象、事件和事件處理函數。 阻止冒泡因為大部分瀏覽器都是按照DOM Leavl 1綁定事件方式,采用的全都是事件冒泡方式。所以阻止事件冒泡(嵌套元素中傳播)是很有必要的。如下方案: 阻止冒泡方案: function cancelPropagation (event){ event = window.event||event; if( document.all){ event.cancelBubble = true; }else{ event.stopPropagation(); } } stopListening函數使用 //這里我們采用上面介紹過的事件處理函數 listenEvent 函數 listenEvent(document.getElementById("oBubble2"),"click",function(evt){ cancelPropagation(evt); }) 阻止冒泡因為IE8、7、6不支持W3C DOM Leavel 2不支持,那么我們就設置event.cancelBubble 的屬性值為 true;而支持其他現代瀏覽器則使用W3C DOM Leavel 2的,則調用stopPropagation方法。 最后羅列文章中出現的幾個Event方法 - W3C DOM Leavl 2綁定和解除事件的方法:addEventListener和removeEventListener:
- IE綁定和解除事件的方法:attachEvent和detachEvent
- 取消事件:W3C DOM Leavl 2使用preventDefault(),iE直接返回false
- 阻止事件在嵌套函數中傳播(阻止冒泡和捕獲):W3C DOM Leavl 2使用stopPropagation(),IE中cancelBubble返回true
本文出現所有DEMO下載:js-attachEvent.rar
|