从AS3中移除ENTER_FRAME事件监听器。

3

这是我的Flash/AS3代码,位于主类中。

addEventListener(Event.ENTER_FRAME,function(e:Event){

        if(findObject == true){
            // I want to remove this ENTER FRAME
        }

});
5个回答

13

尝试这个:

e.currentTarget.removeEventListener(e.type, arguments.callee)

5
  1. 在上面的代码中,你不应该这样做。

  2. 如果事件的currentTarget没有removeEventListener()方法(可能但很少见),那么mgraph的代码有极小的可能无法按照预期工作。从编译器的角度来看,你将尝试动态解析一个通用对象上的方法,这是容易出错的,需要小心处理。这很危险,因为它表明程序员“不知道”她希望处理什么类型的对象,并且是基于假设工作的。假设对于找到解决方案很有用,但对于实施解决方案同样不利。

如果你想要优化某些东西,那么请注意,你所做的方式实际上会在符号表(在编译后的SWF文件中)中创建一个唯一的(冗余的)名称,这会导致SWF文件的压缩更差。

如果你只是作为实验,那么这没问题,但在真正的项目中应避免使用这样的代码。

还有一件事需要注意:与true常量进行比较是完全没有意义的。如果这样的比较有任何意义(即findObject可能随时评估为false),那么if(findObject){...}是你代码的等效但更短的版本。

最后一件事,希望你知道匿名函数缺少返回类型声明。在你的例子中,这不会真正改变什么,除了你会得到编译器警告。省略类型声明通常是一种不好的风格。

编辑

public function addEventListener(type:String, listener:Function ...):void
{
    this._listeners[type].push(listener);
}

public function dispatchEvent(event:Event):void
{
    for each (var listener:Function in this._listeners[event.type])
        listener(event);
}

public function removeEventListener(type:String, listener:Function, ...):void
{
    delete this._listeners[type][listener];
}

假设您确实希望实现IEventDispatcher(而不是使用另一个EventDispatcher - 您可能有自己的原因这样做,其中一个原因是本机EventDispatcher生成大量短暂对象 - 事件,您可能想要减少该项)。但是,在您的代码中,您无法复制event.target或event.currentTarget,因为您无法访问拥有该方法的对象,因此,您可以将其留空。
另一个例子:
public class SomeEvent extends Event
{

    private var _target:NotEventDispatcher;

    public function SomeEvent(type:String, someTarget:NotEventDispatcher)
    {
        super(type);
        this._target = someTarget;
    }

    public override function get target():Object
    {
        return this._target;
    }
}

这是我在现实世界中看到的东西,它被用于Mate或类似框架中,以将所有事件分发器“匿名”连接到某个“母船事件分发器”的单个静态实例。
我并不一定支持这种方法,但从技术上讲,你可以做其中任何一种。我在上面的帖子中说的是,在某些情况下,语言会向你承诺一些事情,比如:如果你执行了:
var dispatcher:IEventDispatcher;
try
{
    dispatcher = IEventDispatcher(event.currentTarget);
    // now you can be sure this object has removeEventListener
    dispatcher.removeEventListener(event.type, arguments.callee);
}
catch (error:Error)
{
    // but what are you going to do here?
}

但最常见的情况是您订阅了一个冒泡事件,在这种情况下,您不知道是否要取消订阅event.target还是event.currentTtarget - 因为您不知道正在侦听哪个。


我很好奇currentTarget不是EventDispatcher的情况。我不明白这种情况在合理的情况下如何发生... - J. Holmes
我不太明白,如果你在嘲笑IEventDispatcher,那么e.currentTarget就是this,因为它保证有一个removeEventListener,因为它是一个IEventDispatcher。此外,模拟EventDispatcher的更简单方法只是新建一个EventDispatcher。除非你特意去尝试破坏事件堆栈--或者故意不满足事件堆栈的依赖关系--e.currentTarget将始终指向具有定义removeEventListener的实例...对我来说,这是一个不完整的模拟,而不是解决方案的问题。 - J. Holmes
我现在明白你的意思了。 - J. Holmes
我想再强调一下,你真的不应该直接模拟 IEventDispatcher,而是应该代理到一个 EventDispatcher 的实例。原生实现利用受保护的成员来克隆事件,并在事件中设置 targetcurrentTarget - J. Holmes
让我们在聊天中继续这个讨论 - J. Holmes

1

我同意wvxvw的观点。

另一种解决问题的方法是使用一个变量来控制您的ENTER_FRAME事件的“状态”:

private var _state:String;

private function init(e:Event):void {
    addEventListener(Event.ENTER_FRAME, loop, false, 0, true);
}

private function loop(e:Event):void {
    switch(_state) {
        case "play":
            // do play stuff
            // when you want to pause
            // goToPause();
        break;
    }
}

// you can call the method below from a button or whatever you want
private function goToPause():void {
    _state = "pause";
    // do some stuff here
    // when you are done, switch "_state" back to "play"
}

在这个例子中,你会一直监听 ENTER_FRAME 事件,但只有当 _state 变量被设置为 "play" 时才会执行操作。你也可以在 goToPause 方法中移除事件监听器:
private function goToPause():void {
    _state = "pause";
    removeEventListener(Event.ENTER_FRAME, loop);
}

然而,使用“_state”来切换事物的好处在于,您不会最终出现一堆需要跟踪的addEventListeners和removeEventListeners(这取决于您的循环有多复杂)。


0

仅为了与此处提到的其他技术完整性,您正在创建的函数是一个未绑定的闭包,因此您也可以利用该概念引用您的函数和调度程序。

var callback:Function;
var dispacher:IEventDispatcher = this;
addEventListener(Event.ENTER_FRAME, callback = function(e:Event){

        if(findObject == true){
            dispacher.removeEventListener(Event.ENTER_FRAME, callback);
        }

});

应用普通的闭包变量规则。


0

如果您想稍后删除侦听器,就不应使用匿名函数调用。

public function main():void
{
    //...
    //some method, where you add event listener
    //...

    //adding enterFrame event listener
    this.addEventListener(Event.ENTER_FRAME,enterFrameHandler);

    //...

}

private function enterFrameHandler(e:Event)
{

    if(findObject)  // " == true" is not really necessary here.
    {
        // removing enterFrame listener:
        this.removeEventlistener(Event.ENTER_FRAME,enterFrameHandler);
    }
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接