Чтобы передать параметр прослушивателю событий в 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.
-
Расширить класс объекта с помощью специального класса для добавления свойства или просто сделать его динамическим.
Каждый раз вам нужно будет создать новый класс.
-
Использовать анонимную функцию как обработчик событий.
Нет ссылки (и это уродливо). Чтобы удалить слушателя на свободные ресурсы, вы вынуждены делать это внутри самой функции с аргументами .callee.
-
Вызовите другую функцию, используя этот параметр, внутри обработчика событий.
А где в вызове обработчика события идет параметр?
-
Храните обработчик событий в той же области, что и параметр.
Нарушение общего смыслового беспорядка.
-
Инкапсулируйте как определение обработчика события, так и вызов addEventListener в функцию, получающую цель и параметры.
Он может смешивать области, но он близок. Однако вы должны быть осторожны.
... Среди многих других предлагаемых обходных решений.
Все, что я хочу, это просто передать аргумент обработчику событий, чтобы я мог использовать его внутри своей функции, как и любая нормальная функция!
Я прошу слишком много?
Ответы
Ответ 1
Из коробки: для решения этой древней загадки требуется 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);
}
IMHO это простейший, но наиболее надежный способ сделать это.
Ответ 2
вот пример
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);
}
Ответ 3
Передача параметра непосредственно обработчику события невозможна.
Наилучшее приближение - это метод функции factory, IMO
//- Редакция:
Я создал отдельный класс для поддержки параметризованных обработчиков, см. 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 или потомок.
Ответ 4
Я бы немного изменил пример 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;
}
С наилучшими пожеланиями
Ответ 5
Почему бы не использовать AS3-Signals? Передача параметра так же просто, как:
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");
}
}