JS的事件模型


  之前對事件模型還是比較清楚的,許多概念都清晰映射在腦海中。工作之后,一方面使用的局限性,二是習慣於用框架中的各種事件監聽方式,簡單即方便,久而久之,事件的一些概念開始淡出記憶中,就像我現在已經開始淡忘C語言的指針、麥克斯韋方程組、矩陣的變換、最小二乘法等。知識就像五彩繽紛的鵝卵石鋪墊在你前行的道路上,從簡單到深刻,從深刻到領悟,一直 助你漸行漸遠。回頭看看事件模型唄。


一、事件簡介

說到事件,大家可以很快想到很多事件類型,比如:
鼠標事件
鍵盤事件
框架事件 onerror onresize onscroll等
表單事件事件 onblur onfocus等
剪貼板事件 oncopy oncut onpaste
打印事件 onafterprint onbeforeprint
拖動事件 ondrag ondragenter等
media事件 onplay onpause
動畫事件 animationend

UI事件:load 、unload、error、select、resize、scroll

二、事件的三種模型


1、原始事件模型(DOM0級)
  特點:原始事件模型中,事件發生后沒有傳播的概念,沒有事件流。事件發生,立即處理。
監聽函數只是元素的一個屬性值,通過指定元素的屬性值來綁定監聽器。書寫方式有兩種:

  HTML: <input id=”btn” onclick=”func()” />
js : document.getElementsById(‘btn’).onclick = func

  優點:所有瀏覽器都兼容

  缺點:
a、邏輯與顯示沒有分離;
b、相同事件的監聽函數只能綁定一個,后綁定的會覆蓋掉前面的。
c、無法通過事件的冒泡、委托等機制等。

  在當前web程序模塊化開發以及更加復雜的邏輯狀況下,這種方式顯然已經落伍了,所以在真
正項目中不推薦使用,平時寫點demo倒是可以,速度比較快。

2、IE事件模型
特點:IE是將event對象在處理函數中設為window的屬性,一旦函數執行結束,便被置為null
了。
IE的事件模型只有兩步,先執行元素的監聽函數,然后事件沿着父節點一直冒泡到document。
綁定解除監聽函數的方法:
attachEvent( "eventType","handler"),其中evetType為事件的類型,如onclick,注意要加
’on’。
解除事件監聽器的方法是 detachEvent("eventType","handler" );
缺點:就是只能IE自己用,太高冷了。

說明:

  a、IE中不支持事件捕獲,只有事件冒泡。

  b、使用attachEvent()方法時候,事件處理程序會在全局作用域中運行,因此this等於window。這點在編寫跨瀏覽器代碼時候很重要。

  c、添加多個事件的時候,觸發的順序是:后添加的先執行,這點和DOM方法不同。

  d、最好不要添加匿名的函數作為執行的函數,這樣事件無法被移除。DOM也要注意這個問題,因為:

 var btn = document.getElementById('myBtn');
   //添加
   btn.attachEvent("onclcik",function(){
   	  dosomthing();
   });
    
   //移除  !!無法移除,因為兩個匿名函數壓根不一樣 所以把事件寫成handler的形式
   btn.detachEvent("onclcik",function(){
   	  dosomthing();
   });

  

3、 DOM2事件模型
在 W3C 2 級 DOM 事件中規范了事件模型,即 DOM2事件模型。現代瀏覽器(IE9以下不算)都遵
循了這個規范。
特點:
W3C制定的事件模型中,一次事件的發生包含三個過程:
  a、事件捕獲階段。事件被從document一直向下傳播到目標元素,在這過程中依次檢查經過的節
          點是否注冊了該事件的監聽函數,若有則執行。
  b、事件處理階段。事件到達目標元素,執行目標元素的事件處理函數.
  c、事件冒泡階段。事件從目標元素上升一直到達document,同樣依次檢查經過的節點是否注冊
了該事件的監聽函數,有則執行。

   注意:所有的事件類型都會經歷事件捕獲階段,但是只有部分事件會經歷事件冒泡階段,例如
submit事件就不會被冒泡。為了最大程度兼容各種瀏覽器,一般都是將事件處理函程序添加到事件流的冒泡階段。

綁定解除監聽函數的方法:
addEventListener("eventType","handler","true|false");其中eventType指事件類型,注意
不要加‘on’前綴,與IE下不同。
第二個參數是處理函數,
第三個即用來指定是否在捕獲階段進 true捕獲階段 false 只有冒泡階段
監聽器的解除也類似:removeEventListner("eventType","handler","true!false");


兼容IE和現代瀏覽器的事件注冊監聽寫法

var a = document.getElementById('XXX');
if(a.attachEvent){
    a.attachEvent('onclick',func);
}
else{//IE9以上和主流瀏覽器
    a.addEventListener('click',func,false);
}

現有的框架和類庫都會對適應各種瀏覽器做兼容性的封裝,JQuery底層即使用了上面的兼容性寫法。

 

三、事件的捕獲-冒泡機制
DOM2標准中,一次事件的完整過程包括三步:捕獲→執行目標元素的監聽函數→冒泡,在捕獲和
冒泡階段,會依次檢查途徑的每個節點,如果該節點注冊了相應的監聽函數,則執行監聽函數。

以如下HTML結構為例子,執行流程應該是這樣的:

<div id="parent">
       父元素
       <div id="child">子元素</div>
</div>

運行一下一目了然。

var parent= document.getElementById('parent');
	console.dir(parent);
    var child = document.getElementById('child');
    parent.addEventListener('click',function(){alert('父親在捕獲階段被點

擊');},true);//第三個參數為true
    child.addEventListener('click',function(){alert('孩子被點擊了');},false);
 parent.addEventListener('click',function(){alert('父親在冒泡階段被點擊

了');},false);//第三個參數為false

 

  可以看到,第三個即用來指定是否在捕獲階段進 true捕獲階段,false沒有捕獲階段 。
如果不想讓事件向上冒泡,可以在監聽函數中調用event.stopPrapagation()來完成,后面會有應
用的栗子。

四、事件對象

  觸發在DOM上的某個事件時,會產生一個事件對象event,這個對象包含了與事件有關的信息。所有瀏覽器都支持事件對象,主要分為:

1、DOM中的事件對象

兼容DOM的瀏覽器會將一個事件對象傳到事件處理程序中。event對象包含了與創建它的特定事件有關的屬性和方法,一般都不太一樣,但也有些相同的成員。比如

bubbles:表明事件是否冒泡

currentTarget:事件處理程序當前正在處理的事件的那個元素

target:事件的目標,與currentTarget還不太一樣。

preventDefault() :取消事件的默認行為,比如點擊a標簽默認跳轉鏈接,點擊button默認提交

stopPropagation():取消事件進一步捕獲或者冒泡,經常會用到

注意:

只有在事件處理程序執行期間,event對象才會存在;一旦事件處理程序執行完畢,event對象就會被銷毀。

2、IE中的事件對象

與訪問DOM中的event對象不同,訪問IE中的event對象有幾種不同的方式。

在DOM0級方法中,envet對象作為Window對象的一個屬性存在。

注意:

  a、在IE中,window.event.returnValue = false;相當於DO中的preventDefault();

  b、stopPropagation()方法是一樣的。

  c、IE中的event.srcElement相當於DOM中的event.target

 

五、事件委托機制

  委托就是把事件監聽函數綁定到父元素上,讓它的父輩來完成事件的監聽,這樣就把事情“委托
”了過去。在父輩元素的監聽函數中,可通過event.target屬性拿到觸發事件的原始元素,然后
再對其進行相關處理。

 

六、jQuery中的事件監聽方式
  jQuery中提供了四種事件監聽方式,分別是bind、live、delegate、on,對應的解除監聽的
函數分別是unbind、die、undelegate、off。這幾個方法已經對各種瀏覽器的兼容性進行封裝。
具體方法可以查看手冊。
注意幾點:
jQuery推薦事件的綁定都使使用on方法
jQuery默認事件不在捕獲中進行

七、什么是自定義事件
張鑫旭的《js-dom自定義事件》


八、一個簡單例子
點擊彈窗之外任何地方,彈框關閉。


方法:給body綁定事件,在事件的執行函數里關閉彈框;
給彈框元素綁定點擊事件,在事件的執行函數里面組織事件冒泡,即:
event.stopPrapagation();

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM