确保不会多次添加相同的事件侦听器

Posted

技术标签:

【中文标题】确保不会多次添加相同的事件侦听器【英文标题】:make sure the same event listener is not added more than once 【发布时间】:2016-03-24 09:02:59 【问题描述】:

我正在实现一个单例IEventDispatcher 类,但遇到了一个问题,有时我将相同的事件侦听器函数多次添加到我的实例中。我尝试按如下方式保留eventFunctions 的数组,以不多次添加事件,但它似乎没有按预期工作。

private var eventFunctions:Array =[];

    public function addEventListener(type:String, listener:Function, useCapture:Boolean = false, priority:int = 0, useWeakReference:Boolean = false):void 
    if(dispatcher.hasEventListener(type) && eventFunctions.indexOf(listener) > -1)
        trace("adding event listener that already exists " + type + " with function " + listener);
        return;
    

    dispatcher.addEventListener(type, listener,  useCapture, priority, useWeakReference);

【问题讨论】:

您似乎从未填充数组?除其他事项外。还有比你展示的更多吗?如果你有多个事件回调同一个函数怎么办?这种方法也否定了弱引用的好处。 我建议仅在 useweakreference = false 时跟踪事件/侦听器。这是相当重要的。我个人使用 Object 来跟踪事件类型(因为它们都是字符串),然后在我的 Object 键中存储 Vector. 。当 useweakreference 和 usecapture 为 true 时,我也会绕过系统 【参考方案1】:

首先请注意,多次添加监听器没有问题 - 只要对象/调度程序、回调函数和 useCapture 参数相同,它实际上不会添加另一个监听器。

例如:

bob.addEventListener(MouseEvent.CLICK, clickHandler);
bob.addEventListener(MouseEvent.CLICK, clickHandler, false);

function clickHandler(e:Event):void   trace("clicky"); ;

每次点击只会产生 1 个跟踪。

现在,如果您将其更改为:

bob.addEventListener(MouseEvent.CLICK, clickHandler, false);
bob.addEventListener(MouseEvent.CLICK, clickHandler, true); //<-- use capture is true on this one

现在您将获得每次点击的两条轨迹。

现在,如果除了第一点之外,您还需要在单例中跟踪所有听众,我建议您这样做:

//instead of an array, use a dictionary so you can have weak keys that don't prevent your objects from being garbage collected
private static var listeners:Dictionary = new Dictionary(true);

//you need to pass the dispatcher into the function (missing from your question code)
public function addEventListener(dispatcher:EventDispatcher, type:String, listener:Function, useCapture:Boolean = false, priority:int = 0, useWeakReference:Boolean = false):void 

    //check is there a record in the dictionary for this object (array)
    if(listeners[dispatcher])

        //loop through the array and see if there are any matches
        for(var i:int=0;i<listeners[dispatcher].length;i++)
            if(listeners[dispatcher][i] && listeners[dispatcher][i].listener == listener
                && listeners[dispatcher][i].type == type 
                && listeners[dispatcher][i].useCapture == useCapture
                && listeners[dispatcher][i].useWeakReference == useWeakReference)

                trace("adding event listener that already exists " + type + " with function " + listener);
                return;
            
        
    

    //add the listener to the dispatcher
    dispatcher.addEventListener(type, listener,  useCapture, priority, useWeakReference);

    //if no record exists yet, create the array and associate it with this dispatcher
    if(!listeners[dispatcher]) listeners[dispatcher] = new Array();

    //add the parameters just used to the array.
    listeners[dispatcher].push(listener: listener, useCapture: useCapture, useWeakReference: useWeakReference);


//you will need a way to remove the listeners as well
public function removeEventListener(dispatcher:EventDispatcher, type:String, listener:Function, useCapture:Boolean = false):void 
    if(listeners[dispatcher] && listeners[dispatcher].length > 0)

        //loop through the array and see if there any matches
        for(var i:int=0;i<listeners[dispatcher].length;i++)
            if(listeners[dispatcher][i] && listeners[dispatcher][i].listener == listener
                && listeners[dispatcher][i].type == type 
                && listeners[dispatcher][i].useCapture == useCapture)

                //remove the event form the dispatcher
                dispatcher.removeEventListener(type, listener, useCapture);

                //remove the item from the array
                listeners[dispatcher].splice(i,1);

                //if the array is now empty, remove the dictionary item
                if(listeners[dispatcher].length < 1) delete listeners[dispatcher];

                //exit the function now
                return;
            
        
    

【讨论】:

这都是我脑子里写的,所以未经测试,可能有错别字。 如果您使用 useweakreference = true 跟踪事件集,您将破坏 useweakreference 系统。最好不要触摸使用 useweakreference = true 设置的事件(意味着根本不跟踪它们) 接受这一点,因为它回答了发布的问题。我不理解我的问题以及我应该理解的问题,它与我发布的内容并不完全相关,但我现在已经解决了。

以上是关于确保不会多次添加相同的事件侦听器的主要内容,如果未能解决你的问题,请参考以下文章

如何在 Jquery 中多次调用一个函数来添加一个事件监听器而不只是监听最后一个?

为啥 jQuery 选择事件侦听器会触发多次?

将事件侦听器添加到在新窗口中打开的文档中

如何确保使用javascript更新select也会触发onchange事件侦听器?

Unity:为啥添加事件侦听器仅在唤醒功能中起作用?

在 AS3 中向子影片剪辑添加/删除事件侦听器