15

我试过这样做:

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

有谁知道一种方法可以为事件处理程序使用匿名闭包,同时仍然保留删除它们的能力?

4

9 回答 9

36

这是删除我在生产项目中使用的事件侦听器的通用方法


addEventListener
(
    Event.ACTIVATE, 
    function(event:Event):void
    {
        (event.target as EventDispatcher).removeEventListener(event.type, arguments.callee)             
    }
)
于 2008-10-07T19:11:53.010 回答
7

正如已经建议的那样,您可以从闭包本身的侦听器链中删除闭包。这是通过使用 arguments.callee 来完成的:

myDispatcher.addEventListener("click", function(event:Event):void
{
    IEventDispatcher(event.target).removeEventListener(event.type, arguments.callee);

    // Whatever else needs doing goes here
});

这将有效地将闭包变成事件的一次性监听器,一旦事件触发就简单地分离自身。虽然语法上很冗长,但对于那些真正只触发一次(或者您只关心一次)的事件来说,它是一种非常有用的技术,例如 Flex 中的“creationComplete”。我在下载数据时一直使用它,因为我认为内联回调代码更容易理解。这就像隐藏异步性:

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

显然,这是一个抽象的例子,但使用像这样的闭包非常有用。但是它们确实有缺点,例如效率低于命名方法。另一个缺点是,如果需要,您实际上必须存储对闭包的引用。然后必须注意保持该引用的完整性,就像任何其他变量一样。

因此,虽然不同的语法可能有其用途,但它并不总是最好的解决方案。这是一种苹果和橘子的东西。

于 2010-10-08T22:17:20.353 回答
3

您可以将 function() 关键字视为构造函数,每次都创建一个新对象(闭包)。因此,如果您创建闭包只是作为参数并且不在任何地方保留引用,则无法在其他地方获得“相同”的闭包。

显而易见的解决方案是你不喜欢的,在使用之前定义函数。当然,它仍然可以是一个完整的闭包,而不仅仅是一个“类静态”函数。只需在所需的上下文中定义它,并将其分配给局部变量。

于 2008-10-07T18:30:30.737 回答
2

我有时用这个:

var closure:Function = null;
root.addEventListener("click", 
   closure = function () 
   { 
      navigateToURL(ClickURLRequest,"_self"); 
   });

root.removeEventListener("click", closure);
于 2010-07-07T13:45:47.050 回答
0

它与使用定义的函数没有太大不同,但也许这会满足您的需求。请记住,函数是 ActionScript 中的一等对象,您可以将它们作为变量存储和传递。

受保护的函数 addListener()
{
    m_handler = function(in_event:Event) { removeEventListener(MouseEvent.CLICK, m_handler); m_handler=null}
    addEventListener(MouseEvent.CLICK, m_handler)
}
受保护的 var m_handler:函数
于 2008-10-08T18:13:30.787 回答
0

我不确定这是否可行,但值得一试:

root.removeEventListener("click", arguments.callee );

有关它的更多信息,请参阅Flex lang ref

于 2008-10-07T18:52:46.400 回答
0

只是我在 Adob​​e 网站上的 Flex In A Week 教程集中遇到的关于您的代码的旁注。在那里,他们说您应该始终使用事件类型的常量而不是字符串。这样你就得到了错字保护。如果您在事件类型字符串中打错字(比如说“clse”),您的事件处理程序将被注册,但当然不会被调用。相反,请使用 Event.CLOSE 以便编译器捕获拼写错误。

于 2008-10-10T13:20:17.947 回答
0

我发现自己经常这样做,所以我尝试了这个。似乎工作正常。

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);
        })
}
于 2009-06-04T04:05:41.807 回答
-1

我不知道你实际上在做什么,但在这个特定的例子中,也许你可以有一个 _clickEnabled 全局变量。

然后在事件处理程序中,您只需检查 _clickEnabled,如果它为假,您只需return立即检查。

然后,您可以启用和禁用整个事件,而无需分离和重新附加它。

于 2008-10-17T21:17:53.657 回答