25

预期/伪示例:

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),在每个网站、论坛、博客上,无论我在哪里搜索,人们都告诉我没有简单的方法可以做到这一点。他们通常建议:

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

    并非所有类都是动态的。例如,它不适用于 Sprite。

  • 使用自定义类扩展对象的类以添加属性或使其动态化。

    您每次都必须创建一个全新的调整类。

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

    没有参考(而且很难看)。要删除侦听器以释放资源,您必须使用 arguments.callee 从函数本身内部执行此操作。

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

    参数在事件处理程序调用中的哪个位置?

  • 将事件处理程序保持在与参数相同的范围内。

    破坏完全的语义混乱。

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

    它可以混合范围,但它是一个接近的范围。不过,你必须小心。

...在许多其他建议的解决方法中。

我想要的只是将一个参数传递给事件处理程序,这样我就可以在它的函数中使用它,就像任何普通函数一样!

我要求太多了吗?

4

5 回答 5

93

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

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 行将其存储在变量中:

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));

这是一个更详细的动态示例来证明其用途:

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);
}

没有通过动态对象的属性,没有自定义类,没有松散的功能,没有范围重叠。正是逻辑所期望的:您只是将参数传递给它。

要正确删除每个侦听器,您可以稍后这样做:

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);
}

恕我直言,这是最简单但最可靠的方法。

于 2012-11-21T07:53:54.877 回答
8

这是一个例子

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);
}
于 2014-01-23T00:49:57.260 回答
2

为什么不使用 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");
    }
}
于 2012-11-21T07:57:10.720 回答
0

无法将参数直接传递给事件处理程序。

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

//--EDITED:我创建了一个单独的类来维护参数化处理程序,请参阅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.

您可以传入任意数量的参数,但回调方法的第一个参数必须是 Event 类型或后代类型。

于 2012-11-21T07:06:47.393 回答
-1

我会稍微修改一下 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;

然后您可以将参数直接传递给目标处理程序:

    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;
    }

最好的祝福

于 2012-11-21T07:32:17.660 回答