當事件被發送出來之後。Event一般來説都會有一個Flow。 Flow分三個部分:
- Capture(捕獲階段)
- Targeting(目標階段)
- Bubbling(冒泡階段)
其關係圖如下:(來源為http://www.adobe.com/devnet/actionscript/articles/event_handling_as3.html)
值得一提的是,在FLASH裡,只有和UI相關的物件,會有上圖所示的目標及補獲階段的事件流,
一般像是Timer、Loader事件,是直接進入目標階段,並不會有上圖所示的事件流的流程。
在宣告Event時,也可以先指定事件是否要完整的跑完全部的流程。
宣告事件的語法及及參數意義如下:
var event:Event = new Event(type, bubbles, cancelable);
參數說明(官方文件)
- type:String是要發送的事件的識別名稱EX:Event.COMPLETE
- bubbles:Boolean預設值是false,這個值是用來設定是否要有冒泡階段,如果傳false,代表他不會跑完全部的流程,只會從Capture到target階段就停止。
- cancelable:Boolean預設值是false,這個值是用來設定是否這個事件可以被
event.preventDefault();
取消,如果設定為true的話,代表此事件是可以被取消的(稍候在dispatchEvent會更詳述這部份)。
常用的可以取消的事件有(cancelable為true): FocusEvent.MOUSE_FOCUS_CHANGE、FocusEvent.KEY_FOCUS_CHANGE、TextEvent.TEXT_INPUT。
而發送事件則是用這一段程式碼:
var result:Boolean = box.dispatchEvent(event);
在發送事件時,要注意,假使今天我們是在STAGE裡面有一個box物件,那當我們用box.dispatchEvent(event);
即使事件是用box發送的,事件還是會從stage > root > box這樣跑。(請見上圖)
假如在建立Event時,bubbles設為true,那在上圖跑的流程為stage > root > box > root > stage。
而若bubbles設為false,跑的流程則是stage > root > box
當我們用root.dispatchEvent(event);
時
bubbles設為true,上圖跑的流程為stage > root > stage
bubbles設為false,流程為stage > root
由此可知,事件流只會到目標(Target),就會停止往下傳。
假如今天box裡面有一個物件button,若是用box.dispatchEvent(event)
,
button物件是不會接到事件流的。(因為到目標階段便會開始bubbles或停止)
並且假如今天root裡同時有box和box2兩個物件,
假使我們用box.dispatchEvent(event)
,則box2也不會接到事件。
至於第三個在建立Event的參數cancelable,不論值是true或false,都不會影響事件流的流程。
那他的作用是做什麼的呢?
我們可以發現,dispatchEvent
有回傳一個布林值,cancelable就是在影響這個布林值的傳回參數。
今天我們假如要創建一個物件,但是要讓使用者有權力去阻止這個事件發生後的後續發展時,可以這樣寫
if(this.dispathEvent(event)){ trace("success!"); //在這寫後續發展 }
假使使用者在監聽的途中呼叫 event.preventDefault();
,並且EVENT的cancelable為true時,dispatchEvent回傳的值就會是false,便不會執行trace("success!");
那塊區塊。但假使EVENT的cancelable為false時,不論你在事件執行中有沒有呼叫event.preventDefault()
,dispatchEvent回傳的值就會是true。
一般我們會在傳遞事件的途中,去將事件攔截下來。增加監聽事件的程式碼如下
box.addEventListener(MouseEvent.MOUSE_DOWN,parent1Event);
官網關於addEventListener的說明如下
addEventListener(type:String, listener:Function, useCapture:Boolean = false, priority:int = 0, useWeakReference:Boolean = false):void
傳入的參數意義如下:
- type(String):事件名稱
- listener(Function):要執行的Function
- useCapture(Boolean):這個和本篇要說的事件流有關,當今天傳入的值為true,則只能在補獲階段去抓取事件,在冒泡階段是聽不到的。如果將 useCapture 設置為 true,則偵聽器只在捕獲階段處理事件,而不在目標或冒泡階段處理事件。
如果 useCapture 為 false,則偵聽器只在目標或冒泡階段處理事件。
要在所有三個階段都偵聽事件,需註冊 addEventListener 兩次:一次將 useCapture 設置為 true,一次將 useCapture 設置為 false。當今天若useCapture為true時,並不會聽到target階段時的事件,但若為false時,也可以聽到target階段時的事件。假使今天我們用
box.dispatchEvent(event)
;來發送事件,
然後box的監聽事件的useCapture設為true。ex :box
.addEventListener(MouseEvent.CLICK, rootClick, true);
這樣rootClick事件並不會被呼叫到。若box的監聽事件的useCapture設為false 。ex :
box
.addEventListener(MouseEvent.CLICK, rootClick, false);
這樣rootClick事件便會被呼叫到。 - priority(int):若今天同時有很多個監聽器同時監聽同一事件,可用這個值來設定那一個監聽器應該被優先執行。數字愈高代表會愈快執行該事件偵聽程式。
- useWeakReference(Boolean):是否使用弱關連。若是用弱關連,當被監聽的物件所指到的變數被指向記憶體的其他地方,這個關係也會一併被取消(物件會被GC回收)。但如果傳進的值是false,當今天被監聽的物件的其他關連被指向別處時,該物件不會被GC回收,需要手動removeEventListener時,該物件才會被GC回收。
除了上述的幾個參數外,還有幾個函數可以中斷事件流的流程。
那就是stopPropagation()
和stopImmediatePropagation()
那這兩個函數有什麼差別呢?
下圖可以很清楚的解釋差異:
stopPropagation()
:會把同一階層的其他事件跑完才停止。
stopImmediatePropagation()
:立刻停止之後所有的事件流。
假如今天box同時有兩個監聽函數如下
box.addEventListener(MouseEvent.MOUSE_DOWN,eventMouseDownHandler1,false,1); box.addEventListener(MouseEvent.MOUSE_DOWN,eventMouseDownHandler2,false,2);
則由於priority值的關係,eventMouseDownHandler2會先被執行,eventMouseDownHandler1在之後才被呼叫。
那若是在eventMouseDownHandler2裡面呼叫event.stopPropagation()
,eventMouseDownHandler1還是會被執行,才將事件流中斷。
但是若在eventMouseDownHandler2裡面呼叫event.stopImmediatePropagation()
,則eventMouseDownHandler1就不會被呼叫到了