Чтобы передать параметр слушателю событий в 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) на каждом сайте, форуме, блоге, где бы я ни искал, люди говорили мне, что простого способа сделать это не существует. Они обычно предлагают:
Добавьте слушателя к динамическому объекту, где вы можете установить значение для дополнительного свойства и ссылаться на него (e.target.property / e.currentTarget.property) в функции.
Не все классы являются динамическими. Это не будет работать на Sprite, например.
Расширьте класс объекта с помощью пользовательского класса, чтобы добавить свойство или просто сделать его динамическим.
Вам придется каждый раз создавать новый класс настройки.
Используйте анонимную функцию в качестве обработчика событий.
Там нет ссылки (и это некрасиво). Чтобы удалить прослушиватель для свободных ресурсов, вы должны сделать это внутри самой функции с arguments.callee.
Вызовите другую функцию, используя параметр, внутри обработчика события.
И куда в вызове обработчика событий уходит параметр?
Держите обработчик событий в той же области, что и параметр.
Нарушение тотального семантического беспорядка.
Инкапсулируйте определение обработчика событий и вызов addEventListener в функцию, получающую цель и параметры.
Он может смешивать области, но он близок. Вы должны быть осторожны, хотя.
... Среди многих других предлагаемых обходных путей.
Все, что я хочу, это просто передать аргумент обработчику событий, чтобы я мог использовать его внутри своей функции, как и любую обычную функцию!
Я спрашиваю слишком много?
5 ответов
Из коробки: для решения этой древней головоломки требуется всего лишь 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);
}
ИМХО, это самый простой, но самый надежный способ сделать это.
вот пример
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);
}
Почему бы не использовать 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");
}
}
Передача параметра непосредственно в обработчик событий невозможна.
Наилучшее приближение - использование метода фабрики функций, 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 или потомок.
Я бы немного изменил пример Крейндерса:
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;
}
с уважением