Передача параметров прослушивающим/обработчикам событий

Как передать параметры/переменные через прослушиватели событий? Я довольно успешно преодолел эту проблему, используя анонимные функции; который является невероятно простым решением, но в конце дня он пахнет гигантской лазейкой для функциональности, которая, как мне кажется, должна предоставляться изначально в любом случае.

Обычно жизнь продолжалась, но по мере того, как судьба имела это, теперь мне действительно нужно удалить слушателя, и это, когда вы используете анонимную функцию, немного напуган. Итак, еще раз, я пытаюсь понять, как передавать параметры через прослушиватели событий, чтобы прослушиватели событий могли быть удалены, просто ссылаясь на функцию.

Как ни странно, я тоже преодолел эту проблему, но мне это не нравится и надоело ее использовать. По-моему, это запах кода. Но это работает как шарм. Я храню переменную, объект или что-то другое в диспетчерском MovieClip. Итак, если я зацикливаю массив массива данных, создавая эскизы "на лету", я просто храню переменную данных (обычно объект с несколькими свойствами) в фактическом thumbnail MovieClip. Затем я могу получить доступ ко всем данным в методе прослушивания событий, указав:

event.target.data
. В этом примере "данные" - это имя переменной, удерживающей информацию, которую я хочу. Поскольку другая проблема, которая возникает, когда я не использую это, заключается в том, что когда я перебираю массив и создаю миниатюры, которые нажимают для просмотра больших изображений, индекс не является согласованным. В конце цикла ВСЕ удачи будут открывать изображение, используя последний индекс "i". Поэтому, если бы у меня был массив длиной 12, все они загрузили бы 12-е изображение, независимо от того, на какой эскиз вы нажали. Сохраняя данные в самом MovieClip, создается сплошная ссылка, которая никогда не изменяется.

Это беспокоило меня уже некоторое время. В основном, что я хочу знать, - это хорошая практика, есть ли там лучшие решения?

Ниже приведены примеры диеты. При необходимости я могу разместить более подробные примеры. Все примеры изображают эскиз, который загружает большое изображение при нажатии.




Без использования анонимной функции (проблема):

tempThumb.addEventListener(MouseEvent.CLICK, loadImage);

public function loadImage(_event:MouseEvent):void  
{
    // I don't have the variable _url and preparing a hot bath with a cold blade  
}

Использование анонимной функции:

tempThumb.addEventListener(MouseEvent.CLICK, function(_event:MouseEvent) { loadImage("large.jpg"); } );

public function loadImage(_url:String):void  
{
    // I got the variable _url and packing away the razor blades  
}

Без использования анонимной функции, но используя мой вонючий метод Leprechaun хранения данных в MovieClip, отправляющий событие

tempThumb.data = "large.jpg";

tempThumb.addEventListener(MouseEvent.CLICK, loadImage);

public function loadImage(_event:MouseEvent):void  
{
    trace(event.target.data);
    // I can access the variable  
}

Я не опираюсь на терминологию программирования, поэтому я назвал вышеупомянутую Методику Лепрекона. Сохранение/скрытие переменных в объектах для последующего использования/доступа. Он решает все мои проблемы и работает удивительно хорошо. Но, если есть лучший способ сделать это, я хочу знать об этом.

Ответ 1

Если MovieClip должен отслеживать дополнительную информацию, которую вам нужно знать, когда она была нажата, я бы использовал более формализованную версию вашего метода Leprechaun.

Я бы создал новый класс под названием SpecialImage, который расширяет MovieClip и обладает свойством для хранения URL-адреса для загрузки.

В зависимости от того, как создаются ваши SpecialImages, вы можете либо создать их в коде, либо связать MovieClip в своей библиотеке с этим классом.

Это в основном шикарный лепрекон, но поскольку информация напрямую связана с изображением MovieClip, хранение их вместе кажется лучшим.

Ответ 2

(Я думаю, вы захотите прочитать этот ответ.)

Что касается вашего сомнения, вы почувствовали это сами: ваш гнойный вонючий (каламбур). Представьте, что это Sprite вместо MovieClip. Он не является динамическим, поэтому вы не можете добавлять свойства, если не выполняете как сказал Ричард.

Здесь лучшее решение, которое вы хотели, на основе вашего примера:

tempThumb.addEventListener(MouseEvent.CLICK, loadImage("large.jpg"));

public function loadImage(_url:String):Function {
  return function(_event:MouseEvent):void {
    // Now you have both variables _url and _event here!
  }
}

Но вы хотите убрать прослушиватели, поэтому:

var functionLoadImage:Function = loadImage("large.jpg");
tempThumb.addEventListener(MouseEvent.CLICK, functionLoadImage);

public function loadImage(_url:String):Function {
  return function(_event:MouseEvent):void {
    // Now you have both variables _url and _event here!
  }
}

//trace(tempThumb.hasEventListener(MouseEvent.CLICK));
tempThumb.removeEventListener(MouseEvent.CLICK, functionLoadImage);
//trace(tempThumb.hasEventListener(MouseEvent.CLICK));

Ответ 3

Вы можете использовать то, что называется "Делегаты", если вам не нравится хранить данные в целевом элементе. Ни то, ни другое лучше другого. Это в основном просто предпочтение.

Вот пример класса делегата (ничего не встроенного): http://www.actionscript.org/resources/articles/205/1/The-Delegate-Class/Page1.html

Это, вероятно, лучшая идея, если eventdispatcher не является вашим собственным классом. В противном случае сохранение переменной в вашем собственном классе вовсе не плохая идея. Только стиль ООП.

Приветствия.

Ответ 4

Да, я знаю, что вы имеете в виду. То, что я делаю, - это продлить событие и, таким образом, отправить настраиваемое событие. Таким образом, я могу создавать свойства в настраиваемом событии, содержащие необходимые данные. Это кажется чистым, но требует немного усилий. Это не идеальный вариант, но я не знаю значительно лучшего способа.

Ответ 5

Анонимные функции лучше избегать, поскольку они могут сделать код неуклюжим, а иногда и привести к утечке памяти. Я бы использовал пользовательские события, если я также несу ответственность за отправку события, но здесь это не так.

В этом случае я бы сохранил URL-адреса и фрагменты роликов в двух отдельных массивах уровня класса и использовал

var url:String = urlArray[mcArray.indexOf(event.target)];

внутри обработчика события, чтобы получить URL-адрес.

Не то, чтобы что-то не так с хранением данных в мувиклипе, но я не чувствую, что это хороший способ. Но, следуя лучшим практикам, даже когда они усложняют ситуацию, это тоже нехорошо - выбор за вами.

Ответ 6

Вы можете сделать следующее, что в основном является более чистым способом передачи пользовательских данных.

example code:
public function myCustomEvenListener(e:MouseEvent,myCustomData:Object)
{
//Do whatever you wnat with myCustomData Object here...
}
//this is the function where you add event listeners to components..
public function init():void
{
var myCustomObject:Object=new Object();
myCustomObject.url="http://xyz.com/image.jsp";
myCustomObject.anydata="You can Add anything here";

mycomponent.addEventListener(MouseEvent.CLICK,function (e:MouseEvent) : void {
                  myCustomEventListener(e,myCustomObject);
            });

}

Это просто еще один способ использования анонимных функций, хотя....

Ответ 7

Вероятно, лучше сделать пользовательский класс, который расширяет MovieClip для вашего thumnbnail, и присваивает этому миниатюре специальный класс событий, в котором есть место для хранения ваших данных:

Создайте собственный URLEvent, который может хранить свойство url вместе с событием

package{

import flash.events.Event;

public class URLEvent extends Event{

    public var url:String;
    public static const CLICK:String = "URLEventClick"

    public function URLEvent(type:String, url:String = "", bubbles:Boolean = false, cancelable:Boolean=false){
        super(type, bubbles, cancelable);
        this.url = url;
    }

    override public function clone():Event{
        return new URLEvent(type,url,bubbles,cancelable);
    }
  }
}

Создайте собственный класс миниатюр, который может хранить переменную url и отправляет URLEvent при нажатии:

package{

import flash.display.MovieClip;
import flash.events.MouseEvent;

public class Thumbnail extends MovieClip{

    protected var url:String;

    public function Thumbnail(url:String){
        this.url = url;
        addEventListener(MouseEvent.CLICK,clickHandler);
    }

    //the thumbnail captures its own click and dispatches a custom event
    protected function clickHandler(event:MouseEvent):void{
        dispatchEvent(new URLEvent(URLEvent.CLICK,url));
    }

}

Теперь вы можете использовать свой класс Thumbnail для загрузки каждого изображения:

tempThumb.addEventListener(URLEvent.CLICK,tempThumbClickHandler);

function tempThumbClickHandler(event:URLEvent):void{
//we can get the url property direct from the URLEvent
    loadImage(event.url);
}

Этот метод намного лучше подходит для практики ООП, так как вам не нужно знать, какой тип объекта имеет ваш event.target - вы знаете, из типа события, какой тип данных будет отправляться с каждым событием.

Ответ 8

Если бы я искал эту функциональность, и я часто это делаю, я бы сделал tempThumb классом, который нести свойство url. то:

MyThumbClass(event.target).url //in the MouseEvent.CLICK handler

Сильная типизация, простой доступ, чистый синтаксис, низкая сложность.