解析Flex3教程中AS2和AS3之間事件轉(zhuǎn)換
本文和大家重點(diǎn)討論一下Flex3教程中AS2轉(zhuǎn)AS3之事件的轉(zhuǎn)換,AS3的事件與AS2有很大的不同,形勢(shì)更統(tǒng)一,功能更強(qiáng)大。希望本文的介紹能讓你有所收獲。
Flex3教程中AS2轉(zhuǎn)AS3之事件的轉(zhuǎn)換
事件的轉(zhuǎn)換
AS3的事件與AS2有很大的不同,形勢(shì)更統(tǒng)一,功能更強(qiáng)大。
1.監(jiān)聽事件的方式(Handlingtheevents)
在AS2時(shí)代,有幾種監(jiān)聽事件的方式,比如onPress=function(){},addListener(listener)等等,而AS3時(shí)代,統(tǒng)一用一種addEventListener(type:String,listener:Function,useCapture:Boolean=false,priority:int=0,useWeakReference:Boolean=false):void,這是接口IEventDispatcher申明的一個(gè)方法,EventDispatcher類實(shí)現(xiàn)了這個(gè)方法(當(dāng)然還實(shí)現(xiàn)了若干其他方法,這里不盡述),這里舉個(gè)監(jiān)聽元件被按下的AS2,AS3方法對(duì)照的例子:
AS2:  
- mc.onPress=Delegate.create(this,__onPress);
 - ...
 - privatefunction__onPress():Void{
 - //Dosomething
 - }
 - AS3:
 - mc.addEventListener(MouseEvent.MOUSE_DOWN,__onPress);
 - ...
 - privatefunction__onPress(e:MouseEvent):Void{
 - //Dosomething
 - }
 
可以看出,首先不同的地方是AS2直接覆蓋了onPress屬性,讓他調(diào)用__onPress,而AS3是增加一個(gè)監(jiān)聽,并沒有覆蓋什么。說明AS3更靈活,因?yàn)槿绻阌袃蓚€(gè)監(jiān)聽器,AS2會(huì)很難處理。其次,AS2中為了使得監(jiān)聽函數(shù)的作用域(scope)能正確(即是說函數(shù)里面的this要能正確的指到本實(shí)例),通常我們需要用Delegate。而AS3中,不需要使用它,因?yàn)锳S3對(duì)于函數(shù)操作會(huì)自動(dòng)進(jìn)行Delegate,相當(dāng)于系統(tǒng)或者編譯器幫我們調(diào)用了Delegate,由此省去了麻煩,避免了忘記調(diào)用而引入的錯(cuò)誤。AS3中的每個(gè)事件監(jiān)聽函數(shù)都必須接受一個(gè)事件實(shí)例(Evnetinstance,這將在下一節(jié)介紹。
另外,這里看看addEventListener的其他幾個(gè)參數(shù),useCapture是否用在捕獲時(shí)期,這個(gè)在第三節(jié)會(huì)講解;priority優(yōu)先度,同一個(gè)類型的事件,優(yōu)先度越大的監(jiān)聽器,會(huì)越早被調(diào)用,默認(rèn)值為0;useWeakReference是否是弱引用,AS3加入了弱引用的功能,熟悉Java的朋友因該知道這是什么含義,即是指這次引用不會(huì)計(jì)算到引用計(jì)數(shù)中,垃圾回收器會(huì)在一個(gè)對(duì)象沒有被任何其他對(duì)象強(qiáng)引用的時(shí)候,把它回收掉。也就是說,如果這里你用了useWeakReference=true,那么這個(gè)監(jiān)聽器如果沒有別的地方存在對(duì)它的引用的時(shí)候,就會(huì)被回收,不過通常我們都用默認(rèn)值false,因?yàn)閲?yán)格管理的程序,你會(huì)自己記得什么時(shí)候加監(jiān)聽,什么時(shí)候移除監(jiān)聽的。
◆在AS2時(shí)代,移除監(jiān)聽器,對(duì)于上面的例子很簡(jiǎn)單,只需要簡(jiǎn)單的mc.onPress=undefined即可,在AS3中,需要這樣mc.removeEventListener(MouseEvent.MOUSE_DOWN,__onPress),其實(shí)也很方便,你移除剛剛增加的監(jiān)聽,只需要把a(bǔ)ddEventListener函數(shù)替換為removeEventListener函數(shù),前三個(gè)參數(shù)保持不變(我這里的例子第三個(gè)參數(shù)都用了缺省值)。
AS2中,還有其他監(jiān)聽事件的方法,比如Key.addListener這樣的方式,這和AS3的方式有點(diǎn)相似,不同之處在于它是加入object作為監(jiān)聽器,然后調(diào)用object的指定名稱的方法,因此它很動(dòng)態(tài),易出錯(cuò),比如我把object的onKeyDown方法寫成了onkeydown,編譯器不會(huì)報(bào)任何錯(cuò)誤,但是程序運(yùn)行的時(shí)候,可能就不是你想要的效果。
2.事件類(Eventclasses)
前面我們提到了,AS3的事件監(jiān)聽函數(shù)都必須接收一個(gè)事件對(duì)象,不同的事件可能會(huì)接收不同類型的對(duì)象(具體是什么類型,請(qǐng)?jiān)敳閹椭臋n),但是所有事件類都繼承自flash.events.Event類。Flex3教程中不同的事件類型都有他們各自的屬性、方法,你可以從這些屬性方法得到你想要的事件內(nèi)容。比如MouseEvent.stageX讓你知道鼠標(biāo)事件發(fā)生時(shí)鼠標(biāo)在舞臺(tái)上的x坐標(biāo),KeyboardEvent.keyCode讓你知道鍵盤事件發(fā)生時(shí)的按下/釋放的按鍵碼。
有很多屬性、方法是與事件流相關(guān)的,因此我們放入下一節(jié)講解。
3.事件流(Eventflow)
Flex3教程中事件流是AS3引入的新機(jī)制,它讓可視元素的事件監(jiān)聽更靈活強(qiáng)大。
事件上事件流只對(duì)可視元素有效,也就說DisplayObject對(duì)象和其子類對(duì)象才擁有此機(jī)制。究竟什么是事件流呢?
事件流是指一個(gè)事件不光是觸發(fā)自己的監(jiān)聽器,它還會(huì)觸發(fā)自己父元件到舞臺(tái)整個(gè)路徑中的其他節(jié)點(diǎn)的同類監(jiān)聽器,順序是這樣的:***階段(Capture階段)事件從stage到發(fā)生者的父元件路徑中所有元件依次觸發(fā)事件,然后第二階段(Target階段)事件發(fā)生者自己觸發(fā),***第三階段(Bubbling階段),事件從發(fā)生者父類再回溯到stage依次觸發(fā)。如下圖所示:
注意這里的Flow,是指舞臺(tái)上的元件層次結(jié)構(gòu)中的流,對(duì)應(yīng)于DisplayObject.parent和DisplayObjectContainer.getChildAt()所相關(guān)的一個(gè)結(jié)構(gòu)。注意這并不是類繼承關(guān)系的結(jié)構(gòu)。在接觸AS3的初期,這比較難以理解透,這里我舉個(gè)例子,應(yīng)該能夠使得你更好理解:
在AS2時(shí)代,假設(shè)我要做一個(gè)簡(jiǎn)單的窗口,這個(gè)窗口上面只放置了一個(gè)確定按紐,我們?cè)O(shè)想的功能是,首先這個(gè)窗口可以被拖動(dòng),然后用戶點(diǎn)擊確定按紐則關(guān)閉這個(gè)窗口。那么通常,簡(jiǎn)單地我們會(huì)創(chuàng)建一個(gè)MC作為窗體,然后這個(gè)MC里面創(chuàng)建一個(gè)Button,監(jiān)聽Button的onPress事件來關(guān)閉MC,這時(shí)沒問題,然后拖動(dòng)MC的實(shí)現(xiàn),我們通過監(jiān)聽MC的onPress事件來startDrag,問題出現(xiàn)了,由于Button在MC內(nèi),因此MC監(jiān)聽了事件后,Button就接收不到事件了。通常為此,我們得創(chuàng)建一個(gè)背景元件放在那個(gè)MC里面,Button的下面,然后監(jiān)聽那個(gè)背景元件的事件來啟動(dòng)拖動(dòng)。這樣要?jiǎng)?chuàng)建這個(gè)多余的背景元件原因就是,如果一個(gè)元件的父元件監(jiān)聽了事件(這里指鼠標(biāo)事件,有的事件是不同的),那么這個(gè)元件將不會(huì)監(jiān)聽到任何事件。
相當(dāng)于說父元件吃掉了所有子元件的事件。而AS3里面,就不同了,回想一下剛才介紹的事件流的過程,如果用戶點(diǎn)擊了Button,首先會(huì)是stage會(huì)觸發(fā)事件,然后是MC的父元件們,然后是MC,然后是Button,然后再反向循環(huán)一次。如果用戶點(diǎn)擊了MC(比如Button旁邊,MC內(nèi)),則會(huì)是stage->MC父元件->MC->MC父元件->stage,兩種情況,MC都會(huì)得到事件觸發(fā),因此,在AS3時(shí)代,再也不需要?jiǎng)?chuàng)建多余的專門用來監(jiān)聽事件的輔助元件了。代碼也會(huì)變得簡(jiǎn)單。并且capture和bubling階段的不同順序,可以讓你選擇是先于事件觸發(fā)者做動(dòng)作,還是后于它做動(dòng)作。addEventListener(type:String,listener:Function,useCapture:Boolean=false,priority:int=0,useWeakReference:Boolean=false):void方法的第三個(gè)參數(shù),讓你可以指定是否是監(jiān)聽capture階段的事件,false代表監(jiān)聽其他兩個(gè)階段的事件。在removeEventListener方法中,你要指定要移除的監(jiān)聽器是哪個(gè)階段的,缺省值是false。
◆相對(duì)于事件流,F(xiàn)lex3教程中Event類有一系列與之相關(guān)的屬性和方法:
target:此屬性指向事件觸發(fā)者,比如剛才的例子,鼠標(biāo)點(diǎn)擊了Button,那么這個(gè)target就是Button,如果鼠標(biāo)點(diǎn)擊了Button旁邊,MC內(nèi),那么它就是MC。
currentTarget:此屬性指向事件流中,當(dāng)前觸發(fā)事件的元件。比如剛才的例子,鼠標(biāo)點(diǎn)擊了Button,如果你監(jiān)聽了MC的鼠標(biāo)點(diǎn)擊事件,那么在監(jiān)聽MC的監(jiān)聽器里面,這個(gè)currentTarget就指向MC,而在監(jiān)聽Button的監(jiān)聽器里面,這個(gè)currentTarget指向Button。你可以看看事件流的那個(gè)圖,currentTarget實(shí)際上值的順序依次是Stage->ParentNode->Child1Node->ParentNode->Stage。比較起target,對(duì)于每個(gè)事件,target則始終是指事件發(fā)生者,比如圖中的Child1Node。
bubbles:此屬性表示此事件在事件流中是否有bubbling階段,有的事件是沒有這一階段的,比如unload事件,大部分非交互性事件也都沒有bubbling階段。所有事件都擁有capture階段嗎?前面講過了,只有可視元素才擁有事件流的概念,也就是說非可視元素是不可能擁有capture和bubbling階段的。那所有元件的事件,都擁有capture階段?對(duì),是這樣的,bubbles為false的事件雖無bubbles階段,但有capture階段。
cancelable:此屬性表示此事件是否可以取消它的默認(rèn)行為。此屬性與preventDefault()方法相關(guān)。
eventPhase:此屬性表示此事件處于事件流中的哪個(gè)階段,capture,target,bubbling三種階段之一。
type:此屬性表示此事件是什么類型,這個(gè)屬性與addEventListener/removeEventListener的***個(gè)參數(shù)type:String對(duì)應(yīng)。
preventDefault():此方法取消事件的默認(rèn)行為,并不是所有事件都有默認(rèn)行為,也并不是所有事件的默認(rèn)行為都可以取消。一個(gè)事件的默認(rèn)行為是否可取消,可以通過cancelable屬性得知。這里舉個(gè)例子,TextEvent.TEXT_INPUT事件的默認(rèn)行為是把輸入的字符加入到TextField中,此事件行為可以取消,如果你調(diào)用它的preventDefault()方法,那么字符就不會(huì)加入到TextField中。而MouseEvent.MOUSE_DOWN這樣的事件,就沒有可取消的默認(rèn)行為,比如你按下一個(gè)按鈕,已經(jīng)行為已經(jīng)發(fā)生,不能取消,實(shí)際上這個(gè)行為在邏輯上看,也沒有什么可取消的東西,看你怎樣理解了,反正可否取cancelable已經(jīng)表明。
isDefaultPrevented():此方法返回事件的默認(rèn)行為是否已經(jīng)被取消了。
stopPropagation():此方法可停止事件在事件流中的傳播,比如上面提到的例子,假如你在capture階段stage監(jiān)聽器里面調(diào)用了此方法,那么后面的節(jié)點(diǎn)中,都不會(huì)收到事件了。如果你在中途調(diào)用此函數(shù),那么此函數(shù)執(zhí)行后,后面的節(jié)點(diǎn)階段,不會(huì)收到事件。
stopImmediatePropagation():此方法可停止事件在事件流包括當(dāng)前節(jié)點(diǎn)中的傳播,此方法與stopPropagation()的區(qū)別之處在于,stopPropagation()不會(huì)停止當(dāng)前節(jié)點(diǎn)的事件觸發(fā),你知道,我們可以給同一個(gè)節(jié)點(diǎn),比如stage加入多個(gè)監(jiān)聽器,如果采用stopPropagation(),那么在你調(diào)用了它之后,同節(jié)點(diǎn)的監(jiān)聽器被觸發(fā)完全之后,事件停止傳播。而stopImmediatePropagation()會(huì)在它被調(diào)用后立即停止傳播,即使是同節(jié)點(diǎn)的事件,也將收不到事件。
總結(jié):
其實(shí)Flex3教程中Event類里面的大部分屬性和方法都與事件流有關(guān),當(dāng)然也就是與可視元素有關(guān)。用戶自己的非可視元素類,也可以有事件,簡(jiǎn)單的繼承EventDispatcher類就可以擁有事件功能,但是,不會(huì)擁有事件流相關(guān)的東西,事件也不會(huì)有capture和bubling階段,只有target階段。當(dāng)然,一般來說普通的類,也不需要這些階段。
【編輯推薦】
















 
 
 
 
 
 
 