ActionScript 3.0 с использованием закрытий для обработчиков событий
Я попытался сделать это:
root.addEventListener("click",
function ()
{
navigateToURL(ClickURLRequest,"_self");
});
И он добавляет прослушиватель событий. Мне нравится использовать закрытие, потому что они хорошо работают в этой ситуации,
однако, удаление прослушивателя событий требует ссылки на исходную функцию, и поскольку я использовал анонимное закрытие, оно не работает, я пробовал:
root.removeEventListener("click",
function ()
{
navigateToURL(ClickURLRequest,"_self");
});
а также:
root.removeEventListener("click", function () {} );
Единственный способ, с помощью которого я нашел, это было бы то, чтобы отбросить анонимное закрытие и указать слушателям событий на ранее существовавшую функцию:
function OnClick (e:Event)
{
navigateToURL(ClickURLRequest,"_self");
}
root.addEventListener("click", OnClick);
root.removeEventListener("click", OnClick);
Кто-нибудь знает способ использования анонимных закрытий для обработчиков событий, сохраняя при этом возможность их удаления?
Ответы
Ответ 1
Вот общий способ удаления прослушивателей событий, которые я использовал в производственных проектах
addEventListener
(
Event.ACTIVATE,
function(event:Event):void
{
(event.target as EventDispatcher).removeEventListener(event.type, arguments.callee)
}
)
Ответ 2
Как уже было предложено, вы можете удалить закрытие из цепочки слушателей из самого закрытия. Это делается с помощью arguments.callee:
myDispatcher.addEventListener("click", function(event:Event):void
{
IEventDispatcher(event.target).removeEventListener(event.type, arguments.callee);
// Whatever else needs doing goes here
});
Это эффективно превратит закрытие в одноразовый слушатель события, просто отделив себя после того, как событие было запущено. Хотя синтаксически многословный, это невероятно полезный метод для тех многих событий, которые действительно срабатывают только один раз (или только вас интересует только один раз), например, "creationComplete" в Flex. Я использую это все время при загрузке данных, так как я думаю, что наличие кода обратного вызова inline облегчает его понимание. Это похоже на скрытие асинхронности:
myLoader.addEventListener("complete", function(event:Event):void
{
/* Even though the load is asynchronous, having the callback code inline
* like this instead of scattered around makes it easier to understand,
* in my opinion. */
});
Однако, если вы хотите прослушивать событие несколько раз, это не будет очень эффективным по понятным причинам. В этом случае вам нужно сохранить ссылку на закрытие где-нибудь. Методы - это объекты, подобные чему-либо еще в ActionScript, и их можно передавать. Таким образом, мы можем изменить наш код так:
var closure:Function;
myDispatcher.addEventListener("click", function(event:Event):void
{
closure = arguments.callee;
// Whatever else needs doing goes here
});
Когда вам нужно удалить прослушиватель событий, используйте ссылку "закрыть", например:
myDispatcher.removeEventListener("click", closure);
Очевидно, что это абстрактный пример, но использование таких закрытий может быть весьма полезным. Однако у них есть недостатки, такие как менее эффективные, чем названные методы. Другим недостатком является тот факт, что вам действительно нужно хранить ссылку на закрытие, если вам когда-либо понадобится. Затем следует соблюдать осторожность, чтобы сохранить целостность этой ссылки, как и с любой другой переменной.
Таким образом, хотя различный синтаксис может иметь свои применения, это не всегда лучшее решение. Это яблоко и апельсины.
Ответ 3
Вы можете думать о ключевом слове function() как о конструкторе, каждый раз создавая новый объект (замыкание). Поэтому, если вы создаете закрытие только для параметра и не сохраняете ссылку нигде, нет никакого способа удержать "то же" закрытие где-то еще.
Очевидное решение - это то, что вам не нравится, определяя функцию перед ее использованием. Конечно, это может быть полное закрытие, а не просто "статичная" функция. просто определите его в нужном вам контексте и назначьте его локальной переменной.
Ответ 4
Я иногда использую это:
var closure:Function = null;
root.addEventListener("click",
closure = function ()
{
navigateToURL(ClickURLRequest,"_self");
});
root.removeEventListener("click", closure);
Ответ 5
Я не уверен, что это сработает, но его стоит сделать:
root.removeEventListener("click", arguments.callee );
Более подробную информацию о нем можно найти Flex lang ref
Ответ 6
Это не слишком сильно отличается от использования определенной функции, но, возможно, это удовлетворит ваши потребности. Помните, что функции являются первоклассными объектами в ActionScript, и вы можете хранить их и передавать их как переменные.
protected function addListener()
{
m_handler = function(in_event:Event) { removeEventListener(MouseEvent.CLICK, m_handler); m_handler=null}
addEventListener(MouseEvent.CLICK, m_handler)
}
protected var m_handler:Function
Ответ 7
Просто обратите внимание на свой код, который я натолкнулся на набор учебных пособий Flex In A Week на веб-сайте Adobe. Там они сказали, что вы всегда должны использовать константы для типов событий, а не для строки. Таким образом, вы получите опечатку. Если вы создадите опечатку в строке типа события (например, say "clse" ), ваш обработчик событий будет зарегистрирован, но, конечно, никогда не будет вызван. Вместо этого используйте Event.CLOSE, чтобы компилятор обнаружил опечатку.
Ответ 8
Я обнаружил, что делаю это много, поэтому я попробовал это. Кажется, что это нормально.
addSelfDestructiveEventListener('roomRenderer', 'complete', trackAction, 'floorChanged');
private function addSelfDestructiveEventListener(listenee:*, event:String, functionToCall:Function, StringArgs:String):void
{
this[listenee].addEventListener(event, function(event:Event):void
{
(event.target as EventDispatcher).removeEventListener(event.type, arguments.callee);
functionToCall(StringArgs);
})
}
Ответ 9
Я не знаю, что вы на самом деле делаете, но в этом конкретном примере, возможно, вы могли бы иметь глобальную переменную _clickEnabled.
Затем внутри обработчика событий вы просто проверяете _clickEnabled, и если его false, вы просто return
немедленно.
Затем вы можете включить и отключить общее событие без отсоединения и повторного подключения.