要传递参数给AS3中的事件监听器,简单的方法是…它存在吗?

预期/伪示例:

stage.addEventListener(MouseEvent.CLICK, onClick.someWayToPassParameters(true, 123, 4.56, "string")); function onClick(e:MouseEvent):void { trace("Received " + someWayToRetrieveParameters().b/i/n/s + "."); } 

多年来(3〜4年),在每一个网站,论坛,博客上,无论我在哪里search,人们告诉我没有简单的方法来做到这一点。 他们通常build议:

  • 将侦听器添加到dynamic对象,您可以在其中将该值设置为一个额外的属性,并在该函数中引用它(e.target.property / e.currentTarget.property)。

    并不是所有的类都是dynamic的 例如,它在Sprite上不起作用。

  • 使用自定义类扩展对象的类以添加属性或使其变为dynamic。

    你必须每次创build一个全新的调整类。

  • 使用匿名函数作为事件处理程序。

    没有参考(这是丑陋的)。 要删除监听器以释放资源,你必须使用arguments.callee从函数本身内部完成。

  • 在事件处理程序中使用参数调用另一个函数。

    而在事件处理程序调用的地方去参数呢?

  • 将事件处理程序保存在与参数相同的作用域中。

    违背语义混乱。

  • 在接收目标和参数的函数中封装事件处理程序定义和addEventListener调用。

    它可以混合使用示波器,但是它非常接近。 但是你必须小心。

…其他许多build议的解决方法。

我只想传递一个参数给事件处理函数,所以我可以在函数内部使用它,就像任何普通的函数一样!

我要求太多吗?

开箱即用:它只需要额外的两行优雅代码来解决这个古老的难题。

 stage.addEventListener(MouseEvent.CLICK, onClick(true, 123, 4.56, "string")); function onClick(b:Boolean, i:int, n:Number, s:String):Function { return function(e:MouseEvent):void { trace("Received " + b + ", " + i + ", " + n + " and " + s + "."); }; } 

但最重要的是,您很可能需要稍后移除侦听器来释放资源,所以+1行将其存储在一个variables中:

 var functionOnClick:Function = onClick(true, 123, 4.56, "string"); stage.addEventListener(MouseEvent.CLICK, functionOnClick); function onClick(b:Boolean, i:int, n:Number, s:String):Function { return function(e:MouseEvent):void { trace("Received " + b + ", " + i + ", " + n + " and " + s + "."); }; } 

你将可以正常移除它:

 trace("Before: " + stage.hasEventListener(MouseEvent.CLICK)); stage.removeEventListener(MouseEvent.CLICK, functionOnClick); trace("After: " + stage.hasEventListener(MouseEvent.CLICK)); 

下面是一个更加详细的,dynamic的例子来certificate它的使用:

 function onClick(s:String):Function { return function(e:MouseEvent):void { trace("The square " + s + " at x = " + e.currentTarget.x + "px was clicked"); }; } var myFunctions:Array = new Array(); for (var i:int = 0; i < 10; i++) { myFunctions.push(onClick("#" + (i+1))); } for (i = 0; i < myFunctions.length; i++) { var square:Sprite = new Sprite(); square.name = "sqr" + i; square.addChild(new Bitmap(new BitmapData(20, 20, false, 0))); square.x = 5 + 25 * i; square.addEventListener(MouseEvent.CLICK, myFunctions[i]); stage.addChild(square); } 

没有属性通过dynamic对象,没有自定义类,没有松散的function,没有范围重叠。 只是逻辑期望它是什么:你只是传递参数。

为了正确地移除每个听众,你可以稍后做这个事情:

 for (i = 0; i < myFunctions.length; i++) { square = stage.getChildByName("sqr" + i) as Sprite; trace("Before (#" + (i+1) + "): " + square.hasEventListener(MouseEvent.CLICK)); square.removeEventListener(MouseEvent.CLICK, myFunctions[i]); trace("After (#" + (i+1) + "): " + square.hasEventListener(MouseEvent.CLICK)); stage.removeChild(square); } 

恕我直言,这是最简单但最坚实的方式来做到这一点。

这里是一个例子

 var s1:Boolean = true; station1.addEventListener(MouseEvent.ROLL_OVER, function(e:MouseEvent) : void { spread(e, s1) }); station1.addEventListener(MouseEvent.ROLL_OUT, function(e:MouseEvent) : void { collapse(e, s1) }); function spread(event:MouseEvent ,bb:Boolean):void { if(bb != true) event.currentTarget.gotoAndPlay(2); } function collapse(event:MouseEvent,bb:Boolean ):void { if(bb != true) event.currentTarget.gotoAndPlay(18); } 

直接传递参数给事件处理程序是不可能的。

最好的近似值是使用函数工厂方法IMO

/ /编辑:我创build了一个单独的类来维护参数化处理程序,请参阅https://gist.github.com/4124722

用法很简单:

  public class Usage extends Sprite{ private var _handlers : ParameterizedHandlerContainer; public function ParameterizedEvents() { _handlers = new ParameterizedHandlerContainer(); _handlers.registerHandler( this, Event.ADDED_TO_STAGE, someMethod, 3000 ); } private function someMethod( event : Event, amount : uint ):void { trace( this, 'someMethod', amount ); _handlers.destroyHandler( arguments.callee, event ); } } 

现在,您可以使用ParameterizedHandlerContainer#registerHandler注册参数化的处理程序,并使用ParameterizedHandlerContainer#destroyHandler销毁它们。

您可以传入任意数量的参数,但callback方法的第一个参数必须是Event或Descendanttypes。

我会稍微修改Creynders的例子:

  protected function createHandler(handler:Function, ...args):Function { var h:Function = function(e:Event = null):void { trace(args); if (handler != null) handler(e); } return h; } sm.addEventListener(StyleEvent.STYLE_CHANGE, createHandler(updateStyle, 1,true,"Lorem",["a","b","c"]), false, 0, true); 

这样你就可以使用原始的事件处理程序并向其中注入“参数”

你也可以让你的处理程序有以下签名:

 protected function myHandler(e:Event, ...args):void; 

那么你可以直接将parameter passing给目标处理程序:

  protected function createHandler(handler:Function, ...args):Function { var h:Function = function(e:Event = null):void { //trace(args); if (handler != null) { args.unshift(e); handler.apply(this, args); } } return h; } 

最好的祝福

为什么不使用AS3信号? 传递一个参数就像下面这样简单:

 import org.osflash.signals.Signal; public class AlarmClock { public var alarm:Signal; public function AlarmClock() { alarm = new Signal(String); } public function ring():void { alarm.dispatch("9 AM"); } }