1. 程式人生 > >AS3.0的事件機制(詳細)

AS3.0的事件機制(詳細)

(1)事件是一個物件,它由flash play產生和管理。事件流分捕獲階段,目標階段和冒泡階段。事件流的示意圖如下,這裡說明一下target和 currentTarget的概念。當一個事件流產生時,就產生了一個顯示物件列表,而target是最裡層的物件,而 currentTarget是捕獲階段和冒泡階段被"遍歷"的顯示物件,當然它只有註冊了時間監聽器,我們才能獲得 event.currentTarget。 
(2)不是所有的事件都有這三個階段。如Timer、URLLoader,它們的事件物件將直接派送給目標物件(target).它們只包含目標階段而沒有捕獲階段和冒泡階段。它們不會像顯示物件容器(DisplayObjectContainer)那樣有可能被一個DisplayObjectContainer物件包含或者自己包含一個DisplayObjectContainer物件,它們往往是單獨存在的。也就是說如果一個顯示物件不在顯示列表中時,FlashPlaye會把事件直接派送給它,這個時候就沒有事件流,也沒有捕獲階段和冒泡階段,只有目標階段。




  [color=ize:18px]
(1)請仔細看上面的圖中的事件流,圖中的假定的事件派發的物件是子節點1,從圖中我們可以看出,事件流並沒有經過子節點2,也就是說如果子節點2中監聽事件,那子節點無法監聽到事件。
(2)如果如果父節點監聽子節點1的事件可以監督到嗎?當然可以因為事件流有經過父節點;有兩種方式可以監聽到子節點1的事件: 
自定義事件: 
    1)在父節點裡面用子節點監聽事件(如子節點1.addEventListener(。。。。))此時不需要設定addEventListener中的useCapture引數和new Event時Event的bubbles引數。就可以直接監聽到子節點1的事件,因為此時直接在目標階段捕捉事件。
    2)直接用在父節點中加入但是addEventListener(。。。)也可以監聽子節點1的事件,但是前提條件是在父節點監聽事件的時候要把addEventListener中的useCapture引數設定成true(如addEventListener(MenuEvent.MENU_Event, handler,true)或者位元組點1中new Event時將Event的bubbles引數設定為true( new MenuEvent(MenuEvent.MENU_Event,true))。如果都不這樣的話,父節點是無法監聽到事件的。


  因為addEventListener中的useCapture的default模式是false也就是偵聽器只在目標或冒泡階段處理事件,而new Event時將Event的bubbles引數default也是false也就是說不參與事件流的冒泡階段。如果不設定useCapture或者bubbles為true那父節點肯定無法監聽到事件。
(3)如果非要在子節點2中監聽子節點1中發出的事件怎麼辦? 
    1)辦法有很多種,說一下最常用的一種,就是向子節點1 與子節點2 都傳入一個相同的物件的例項,在子節點1中用這個物件例項發出事件,在子節點2中用這個物件例項監聽事件(在目標階段捕獲事件)。這樣就可以收到位元組點1的事件了。

非自定義事件(如mouseEvent): 
   1)當是非自定義事件時。直接用在父節點中加入但是addEventListener(。。。)就可以監聽子節點1的事件。 
   2)有人可能要問如果我要在子節點2監聽子節點1的非自定義事件呢?可以用(上面的2 標題裡面 3)),但是完全沒有必要,比如,你說你在子節點2中監聽子節點1的mouseClick 事件幹嗎??


摘錄Flash幫助文件中的規範解釋:

addEventListener () 方法 

public function addEventListener(type:String, listener:Function, useCapture:Boolean = false, priority:int = 0, useWeakReference:Boolean = false):void

語言版本 : ActionScript 3.0 
RuntimeVersions: AIR 1.0, Flash Player 9 

使用 EventDispatcher 物件註冊事件偵聽器物件,以使偵聽器能夠接收事件通知。可以為特定型別的事件、階段和優先順序在顯示列表的所有節點上註冊事件偵聽器。

成功註冊一個事件偵聽器後,無法通過額外呼叫 addEventListener() 來更改其優先順序。要更改偵聽器的優先順序,必須首先呼叫 removeListener()。然後,可以使用新的優先順序再次註冊該偵聽器。

請記住,註冊該偵聽器後,如果繼續呼叫具有不同 type 或 useCapture 值的 addEventListener(),則會建立單獨的偵聽器註冊。例如,如果首先註冊 useCapture 設定為 true 的偵聽器,則該偵聽器只在捕獲階段進行偵聽。如果使用同一個偵聽器物件再次呼叫 addEventListener(),並將 useCapture 設定為 false,那麼便會擁有兩個單獨的偵聽器:一個在捕獲階段進行偵聽,另一個在目標和冒泡階段進行偵聽。

不能只為目標階段或冒泡階段註冊事件偵聽器。這些階段在註冊期間是成對出現的,因為冒泡階段只適用於目標節點的始祖。 

如果不再需要某個事件偵聽器,可呼叫 removeEventListener() 刪除它,否則會產生記憶體問題。由於垃圾回收器不會刪除仍包含引用的物件,因此不會從記憶體中自動刪除使用已註冊事件偵聽器的物件。

複製 EventDispatcher 例項時並不複製其中附加的事件偵聽器。(如果新近建立的節點需要一個事件偵聽器,必須在建立該節點後附加該偵聽器。) 但是,如果移動 EventDispatcher 例項,則其中附加的事件偵聽器也會隨之移動。

如果在正在處理事件的節點上註冊事件偵聽器,則不會在當前階段觸發事件偵聽器,但會在事件流的稍後階段觸發,如冒泡階段。 

如果從正在處理事件的節點中刪除事件偵聽器,則該事件偵聽器仍由當前操作觸發。刪除事件偵聽器後,決不會再次呼叫該事件偵聽器(除非再次註冊以備將來處理)。 


引數 type:String — 事件的型別。 

listener:Function — 處理事件的偵聽器函式。此函式必須接受 Event 物件作為其唯一的引數,並且不能返回任何結果,如下面的示例所示: 
function(evt:Event):void函式可以有任何名稱。 


useCapture:Boolean (default = false) — 確定偵聽器是運行於捕獲階段、目標階段還是冒泡階段。如果將 useCapture 設定為 true,則偵聽器只在捕獲階段處理事件,而不在目標或冒泡階段處理事件。如果 useCapture 為 false,則偵聽器只在目標或冒泡階段處理事件。要在所有三個階段都偵聽事件,請呼叫 addEventListener 兩次:一次將 useCapture 設定為 true,一次將 useCapture 設定為 false.

priority:int (default = 0) — 事件偵聽器的優先順序。優先順序由一個帶符號的 32 位整數指定。數字越大,優先順序越高。優先順序為 n 的所有偵聽器會在優先順序為 n -1 的偵聽器之前得到處理。如果兩個或更多個偵聽器共享相同的優先順序,則按照它們的新增順序進行處理。預設優先順序為 0。

useWeakReference:Boolean (default = false) — 確定對偵聽器的引用是強引用,還是弱引用。強引用(預設值)可防止您的偵聽器被當作垃圾回收。弱引用則沒有此作用。
類級別成員函式不屬於垃圾回收的物件,因此可以對類級別成員函式將 useWeakReference 設定為 true 而不會使它們受垃圾回收的影響。如果對作為巢狀內部函式的偵聽器將 useWeakReference 設定為 true,則該函式將作為垃圾回收並且不再是永久函式。如果建立對該內部函式的引用(將該函式儲存到另一個變數中),則該函式將不作為垃圾回收並仍將保持永久。

                                                   轉載請註明來自:http://www.shengshiyouxi.com