JS 事件學習筆記(一),js事件學習筆記
一 事件流
如果說某個元素有祖先元素,其祖先元素和它都定義了相同的事件,那麼在該元素上發生某個事件的時候,涉及到事件在該元素和祖先元素間的行程順序問題。
分為兩種:
事件冒泡:從最具體的元素開始接收,執行事件處理常式,然後把該事件往上傳遞一直到document對象。
如果在某個元素上觸發了某個事件,則會調用其事件處理常式,若該元素沒有定義事件處理常式或者事件返回true,則會交由父級對象處理,從裡到外,所有父級對象的同類事件都會被啟用。一直上傳到document對象為止。
事件捕獲:相反,從最外層的document先捕獲再依次往最具體的元素傳遞。即內部元素中觸發了某個事件後,先由外部元素”截獲“該事件,並執行自己綁定的事件處理常式。再將該事件向下傳遞給內部元素。
通常都使用事件冒泡。
DOM2級事件流
分為三個階段:捕獲階段、處於目標階段(實際目標接收到事件)、事件冒泡階段(在該階段讓具體目標對事件作出響應)。也就是說事件首先從document往下傳遞,一直到目標對象,然後再以起泡方式往上傳遞到document。但是包含元素具體在哪個階段執行事件處理常式是由添加事件的函數的參數來設定的。也就是說父元素一定是先接收到事件的,但是不一定在截獲的時候就執行。
多數支援dom事件流的瀏覽器都遵循規定:在捕獲階段不涉及事件目標,但chrome、Firefox、IE9等瀏覽器可在捕獲階段觸發事件對象上的事件,結果就是有兩個機會(階段)在目標對象上操作事件。
二 事件處理常式A. html事件處理常式
即相應某個事件的函數,以”on“開頭。事件處理常式中的代碼在執行時有權訪問全域範圍中的任何代碼。
函數中有一個不用自訂的局部變數even,即事件對象;函數中的this指向事件的目標元素。
擴充範圍:with語句
該方式的缺點p-350
B. JavaScript指定事件處理常式
1. DOM0級事件處理常式
該方式讓js代碼和html緊密耦合。應使用JavaScript指定事件處理常式:將函數賦值給要操作對象的事件處理常式屬性。如btn.onclick=function(){}。
注意:在JS代碼運行到綁定事件前不會指定任何事件處理常式,因此若這些代碼在頁面中位於按鈕的後面則可能在一段時間內點擊按鈕沒有反應。
該方式指定的事件處理常式被認為是元素的方法,是在元素的範圍中運行,this引用當前元素。以該方式指定,會在事件流的冒泡階段被處理。DOM0級在一個DOM元素上對同一種事件只支援一個事件處理常式,後面的會覆蓋前面的事件處理常式(可在一個DOM元素上綁定不同的事件)。
刪除綁定的事件:btn.onclick=null
2 . DOM2級事件處理常式
為DOM結點規定了方法addEventListener()和removeEventListener()用於設定和刪除事件處理常式,這兩個方法都包含三個參數:
- 參數一:指定事件名稱
- 參數二:指定事件處理常式
- 參數三:布爾值,true表示接收該事件的對象在事件捕獲階段就呼叫事件處理常式,false表示接收到該事件的對象要等到在冒泡階段才調用。例如:
//html代碼<div id="outside">I am outside<div id="inside">I am inside</div></div>//js代碼window.onload=function(){ var outside = document.getElementById("outside"); outside.addEventListener("click",function(){alert("I am outside")},true);//在捕獲階段就調用 var inside = document.getElementById("inside"); inside.addEventListener("click",function(){alert("I am inside")},true);}
如上面的代碼,外面的盒子outside的事件處理常式設定為true,則是在捕獲階段如果截獲到該事件了,就立即調用其事件處理常式,也就是說如果點擊了內部盒子,則輸出順序為”I am outside”,”I am inside“。
若將外部盒子的true改為false,意思是在冒泡階段才調用處理常式,則點擊內部盒子後,輸出順序為”I am inside“,”I am outside”。
該方式仍是在所依附的元素的範圍中進行。該方式的優點是可以添加多個事件(包括同名的不會被覆蓋),按照添加的先後順序執行。
注意:removeEventListener()的參數和addEventListener的相同,但是匿名函數無法移除,也就是說事件根本沒有解除綁定,仍然點擊有效。實際上這個函數與傳入addEventListener中的匿名函數完全是兩個,可通過傳入持有匿名函數引用的變數來解決:
IE中只有IE9支援DOM2級方法。
<script type="text/javascript">window.onload=function(){ var btn = document.getElementById("show"); var handler = function(){alert(this.value)}; btn.addEventListener("click",handler,false); btn.removeEventListener("click",handler,false);}</script>
為了最大限度相容各種瀏覽器,最好將事件處理常式添加到事件流的冒泡階段,只在需要在事件達到目標之前截獲它的時候將事件處理常式添加到捕獲階段。
3.IE事件處理常式
IE實現了兩個方法:attachEvent()和detachEvent(),添加的事件處理常式被添加到冒泡階段。與DOM0以及DOM2級的區別是事件處理常式的範圍不是其所屬的元素(this==綁定事件的元素),而是全域,即this==window。同樣可以為一個元素添加多個事件,但是執行的順序是後添加的先執行。detachEvent用於解除事件,同樣匿名函數參數不能解除,應當傳遞其引用。
IE8及以下的程式處理函數執行順序與綁定的順序相反,而其他IE瀏覽器則是正常的。
<script type="text/javascript">window.onload=function(){ var out = document.getElementById("outside"); out.attachEvent("onclick",function(){alert("I am outside")}); //注意此處是“onclick”而非“click” var inside = document.getElementById("inside"); inside.attachEvent("onclick",function(){alert("I am inside")});}</script>
4.跨瀏覽器事件處理常式
var EventUtil={ addHandler:function(element,type,handler){ if(element.addEventListener){ //DOM2級方法 element.addEventListener(type,handler,false); }else if(element.attachEvent){ //IE方法 element.attachEvent("on"+type,handler); }else{ //DOM0級 element["on"+type]=handler; } }, removeHandler:function(element,type,handler){ if(element.removeEventListener){ element.removeEventListener(type,handler,false); }else if(element.detachEvent){ element.detachEvent("on"+type,handler); }else{ element["on"+type]=null; } }};
三 禁止事件冒泡
先說幾個相關的方法和屬性:
- cancelBubble(HTML DOM Event對象的屬性):如果事件控制代碼想阻止事件傳播到包容對象,必須把該屬性設為 true。
- stopPropagation(HTML DOM Event 對象方法):終止事件在傳播過程的捕獲、目標處理或起泡階段進一步傳播。調用該方法後,該節點上處理該事件的處理常式將被調用,事件不再被指派到其他節點。
可將阻止事件冒泡的程式寫成下列函數:
function stopBubble(e){ if(e && e.stopPropagation){ e.stopPropagation(); //DOM }else{ window.even.cancelBubble=true; //IE }}
把這個stopBubble(e)函數放到你想要的阻止事件冒泡函數裡面就可以阻止事件冒泡了。
四 事件對象
1. DOM事件對象
在現代瀏覽器中,會為事件處理常式傳入一個event對象作為參數,而IE瀏覽器按DOM0級方式綁定事件時,event是window對象的屬性,而按照其他方式則是事件處理函數的參數。
不同的事件具有不同的屬性和方法,但在現代瀏覽器中,所有事件對象都具有下列屬性和方法:
- currentTarget屬性:事件處理常式正在處理事件的那個元素(即正在呼叫事件處理常式的元素),this始終等於currentTarget。而target屬性指向最具體的那個目標,即實際被觸發了事件的那個元素。
<script type="text/javascript">var outside = document.getElementById("outside");var inside = document.getElementById("inside");outside.onclick=function(event){ //傳遞event參數 alert("I am outside"); alert("this==event.currentTarget? " + (this===event.currentTarget)); //+優先順序高於=== alert("event.target==this? " + (event.target===this)); alert("event.target==inside? " + (event.target===inside));};inside.onclick=function(event){ alert("I am inside"); alert("this==event.currentTarget? " + (this===event.currentTarget)); alert("event.target==this? " + (event.target===this)); alert("event.target==inside? "+ (event.target===inside));};</script>
- type屬性:事件的類型
- preventDefault():阻止事件觸發時的預設行為,例如點擊超連結被頁面跳轉到url指定的頁面。只有cancelable屬性設定為true的事件才可使用該方法。
- eventPhase屬性:事件處理常式被調用時是處於哪個階段。1為捕獲階段、2為在目標對象上、3為冒泡階段。
event對象只有在事件處理常式運行過程中才存在,運行完畢即銷毀。
2. IE中的事件對象
IE中事件對象的方式有幾種,取決於添加事件的方法。如果使用DOM0級方法,則event對象作為window對象的一個屬性,應當以window.event這樣的方式來使用。如果使用attachEvent()方法,則event作為事件處理函數的參數,當然也可以作為window的屬性。
該對象包括下列屬性和方法:
- cancelBubble屬性:預設為false,設為true則取消事件冒泡
- returnValue屬性:預設為true,設為false則取消事件觸發時的預設行為
- srcElement屬性:與target相同
注意:(1)由於在IE中事件處理常式的範圍由添加它的方式來確定,如果使用DOM0級方式,則this就是調用處理常式的元素,而通過attachEvent指定,則this==window。因此,不能認為this始終會等於事件目標,使用event.srcElement指定事件目標比較保險。
(2) IE不支援事件捕獲,使用cancelBubble就只能取消事件冒泡,而stopPropagation()則捕獲和冒泡都可以取消。
3. 跨瀏覽器的事件對象
DOM和IE中的事件對象不一樣,但它們有很多方法和屬性是對應的。在這裡將EventUtil對象增強,實現跨瀏覽器的事件對象和事件處理常式。
<script type="text/javascript">var EventUtil={ addHandler:function(element,type,handler){ if(element.addEventListener){ //DOM2級方法 element.addEventListener(type,handler,false); }else if(element.attachEvent){ //IE方法 element.attachEvent("on"+type,handler); }else{ //DOM0級 element["on"+type]=handler; } }, removeHandler:function(element,type,handler){ if(element.removeEventListener){ element.removeEventListener(type,handler,false); }else if(element.detachEvent){ element.detachEvent("on"+type,handler); }else{ element["on"+type]=null; } }, getEvent:function(event){ //無論如何傳入event參數,IE中若通過DOM0實現則該event是undefined的 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; } } };</script>
著作權聲明:本文為博主原創文章,未經博主允許不得轉載。