ActionScript 3.0 事件模型與 DOM 事件模型不同的其中一個部分,就是在建立偵聽程式函數這方面。在 DOM 事件模型中,事件偵聽程式與偵聽程式函數之間有著清楚的區別:事件偵聽程式是會實作 EventListener 介面之類別的實體,而偵聽程式函數則是名為 handleEvent() 之類別的方法。在 DOM 事件模型中,您註冊的是包含偵聽程式函數的類別實體,而非實際的偵聽程式函數。
在 ActionScript 3.0 事件模型中,事件偵聽程式與偵聽程式函數之間並沒有清楚的區別。ActionScript 3.0 並沒有 EventListener 介面,因此偵聽程式函數可以在類別之外定義,或是定義為類別的一部分。此外,偵聽程式函數不一定要名為 handleEvent(),而是能以任何有效的識別項來命名。在 ActionScript 3.0 中,您註冊的是實際偵聽程式函數的名稱。
在類別之外定義的偵聽程式函數
下列程式碼會建立簡單的 SWF 檔,並顯示紅色正方形。名為 clickHandler() 的偵聽程式函數 (不屬於類別的一部分) 會偵聽紅色正方形上的滑鼠按一下事件。
package
{
import flash.display.Sprite;
public class ClickExample extends Sprite
{
public function ClickExample()
{
var child:ChildSprite = new ChildSprite();
addChild(child);
}
}
}
import flash.display.Sprite;
import flash.events.MouseEvent;
class ChildSprite extends Sprite
{
public function ChildSprite()
{
graphics.beginFill(0xFF0000);
graphics.drawRect(0,0,100,100);
graphics.endFill();
addEventListener(MouseEvent.CLICK, clickHandler);
}
}
function clickHandler(event:MouseEvent):void
{
trace("clickHandler detected an event of type: " + event.type);
trace("the this keyword refers to: " + this);
}
當使用者按一下該正方形,並與產生的 SWF 檔進行互動時,Flash Player 或 AIR 便會產生下列追蹤輸出:
clickHandler detected an event of type: click
the this keyword refers to: [object global]
請注意,該事件物件會當做引數傳遞給 clickHandler()。這可讓您的偵聽程式函數檢查該事件物件。在此範例中,您會使用該事件物件的 type 屬性,查明該事件為 click 事件。
此範例也會檢查 this 關鍵字的值。在此範例中,this 代表全域物件,這是可以理解的,因為這個函數是在任何自訂類別或物件之外所定義。
定義為類別方法的偵聽程式函數
下列範例與定義 ClickExample 類別的上一個範例完全相同,但是 clickHandler() 函數卻定義為 ChildSprite 類別的方法:
package
{
import flash.display.Sprite;
public class ClickExample extends Sprite
{
public function ClickExample()
{
var child:ChildSprite = new ChildSprite();
addChild(child);
}
}
}
import flash.display.Sprite;
import flash.events.MouseEvent;
class ChildSprite extends Sprite
{
public function ChildSprite()
{
graphics.beginFill(0xFF0000);
graphics.drawRect(0,0,100,100);
graphics.endFill();
addEventListener(MouseEvent.CLICK, clickHandler);
}
private function clickHandler(event:MouseEvent):void
{
trace("clickHandler detected an event of type: " + event.type);
trace("the this keyword refers to: " + this);
}
}
當使用者按一下該紅色正方形,並與產生的 SWF 檔進行互動時,Flash Player 或 AIR 便會產生下列追蹤輸出:
clickHandler detected an event of type: click
the this keyword refers to: [object ChildSprite]
請注意,this 會參考名為 child 的 ChildSprite 實體。這是與 ActionScript 2.0 不同的行為變更。如果您使用 ActionScript 2.0 中的組件,就可能還記得,當類別方法傳遞至 UIEventDispatcher.addEventListener() 中時,該方法的範圍就會限定為廣播該事件的組件,而非在其中定義偵聽程式方法的類別。換句話說,如果您使用這項 ActionScript 2.0 的技巧,this 關鍵字就會參考廣播該事件的組件,而非 ChildSprite 實體。
對某些程式設計人員而言,這是個重大的問題,因為這表示他們無法存取該類別 (包含偵聽程式方法) 的其它方法和屬性。為瞭解決此問題,ActionScript 2.0 的程式設計人員會使用 mx.util.Delegate 類別,變更偵聽程式方法的範圍。不過,因為 ActionScript 3.0 會在呼叫 addEventListener() 方法時建立繫結方法,所以便不再需要上述作法。結果,this 關鍵字便會參考名為 child 的 ChildSprite 實體,如此程式設計人員便能存取 ChildSprite 類別的其它方法和屬性。
不應該使用的事件偵聽程式
此外,還有第三種技巧,您可以使用這項技巧建立一般物件,而且該物件的屬性會指向以動態方式指派的偵聽程式函數,但是這項技巧並不建議使用。我們在此討論它的原因是因為 ActionScript 2.0 常常會用到它,但是在 ActionScript 3.0 請勿使用它。不建議使用這個技巧的原因,是因為 this 關鍵字會參考全域物件而不是您的偵聽程式物件。
下列範例與上一個 ClickExample 類別範例完全相同,但是偵聽程式函數卻定義為名為 myListenerObj 之一般物件的一部分:
package
{
import flash.display.Sprite;
public class ClickExample extends Sprite
{
public function ClickExample()
{
var child:ChildSprite = new ChildSprite();
addChild(child);
}
}
}
import flash.display.Sprite;
import flash.events.MouseEvent;
class ChildSprite extends Sprite
{
public function ChildSprite()
{
graphics.beginFill(0xFF0000);
graphics.drawRect(0,0,100,100);
graphics.endFill();
addEventListener(MouseEvent.CLICK, myListenerObj.clickHandler);
}
}
var myListenerObj:Object = new Object();
myListenerObj.clickHandler = function (event:MouseEvent):void
{
trace("clickHandler detected an event of type: " + event.type);
trace("the this keyword refers to: " + this);
}
追蹤的結果,看起來如下所示:
clickHandler detected an event of type: click
the this keyword refers to: [object global]
您期望 this 會參考 myListenerObj,並且追蹤輸出會是 [object Object],但是它卻改為參考全域物件。當您將動態屬性名稱當做引數傳遞給 addEventListener() 時,Flash Player 或 AIR 便無法建立繫結方法。這是因為您傳遞做為 listener 參數的只不過是偵聽程式函數的記憶體位址,而且 Flash Player 和 AIR 無法將這個記憶體位址與 myListenerObj 實體加以連結。