【问题标题】:Removing an anonymous event listener删除匿名事件侦听器
【发布时间】:2011-03-07 14:28:13
【问题描述】:

有没有办法移除像这样添加的事件监听器:

element.addEventListener(event, function(){/* do work here */}, false);

不替换元素?

【问题讨论】:

  • 如果有多个匿名监听器,您将如何选择合适的删除?
  • @Sean Hogan:什么?我不明白你问的问题与我的问题有什么关系。
  • @Sean:我认为目的是从事件处理程序中删除事件侦听器。

标签: javascript greasemonkey addeventlistener userscripts


【解决方案1】:

除非您在创建时存储了对事件处理程序的引用,否则无法彻底删除事件处理程序。

我通常会将这些添加到该页面上的主要对象中,然后您可以在使用该对象时迭代并干净地处理它们。

【讨论】:

  • 我想知道为什么 addeventlistener 不返回这样的引用以供 removeeventlistener 将来使用...
  • 确实如此,这就是您保存的内容。
  • @Joe 对于迟到的用户:addEventListener 至少在某些情况下返回undefined。例如在 BroadcastChannel 上下文中。
  • 请注意,根据stackoverflow.com/a/27107765/377022,在Chrome控制台中,您可以使用getEventListeners函数
  • @Joe 当然。更新官方接受的答案可能会很好,以便将来将其作为参考的人(就像我一样)了解新的发展。
【解决方案2】:

你可以像这样移除事件监听器:

element.addEventListener("click", function clicked() {
    element.removeEventListener("click", clicked, false);
}, false);

【讨论】:

  • 这仅在您首先添加事件侦听器时才有效——您可以修改原始的 listener() 代码。因为这是一个 Greasemonkey 应用程序,所以这是不可能的。即使更改了基本页面脚本,您也只会添加 另一个 匿名侦听器。
  • @Brock:哦,我以为是要删除你添加的监听器。我不知道有什么方法可以删除你没有添加的监听器并且没有引用的函数。
  • Brock 是正确的,这是一个关于用户脚本的问题,但还是不错的答案,我投了赞成票!
  • 你可能想补充一点,callee 自 ES5 以来已被弃用(请参阅 mdnSO
  • @fxm:谢谢。我不记得为什么我最初使用 arguments.callee 并且命名函数表达式应该可以正常工作,所以我编辑了我的答案。
【解决方案3】:

匿名绑定事件监听器

删除一个元素的所有事件侦听器的最简单方法是将其outerHTML 分配给它自己。它的作用是通过 HTML 解析器发送 HTML 的字符串表示,并将解析的 HTML 分配给元素。因为没有传递 JavaScript,所以不会有绑定的事件监听器。

document.getElementById('demo').addEventListener('click', function(){
    alert('Clickrd');
    this.outerHTML = this.outerHTML;
}, false);
<a id="demo" href="javascript:void(0)">Click Me</a>

匿名委托事件监听器

需要注意的是委托事件侦听器,或父元素上的事件侦听器,用于监视与其子元素匹配的一组条件的每个事件。解决这个问题的唯一方法是更改​​元素使其不符合委托事件侦听器的标准。

document.body.addEventListener('click', function(e){
    if(e.target.id === 'demo') {
        alert('Clickrd');
        e.target.id = 'omed';
    }
}, false);
<a id="demo" href="javascript:void(0)">Click Me</a>

【讨论】:

    【解决方案4】:

    老问题,但这里有一个解决方案。

    严格来说,您不能删除匿名事件侦听器,除非您存储对该函数的引用。由于使用匿名函数的目的可能不是创建新变量,因此您可以将引用存储在元素本身中:

    element.addEventListener('click',element.fn=function fn() {
        //  Event Code
    }, false);
    

    稍后,当您想删除它时,您可以执行以下操作:

    element.removeEventListener('click',element.fn, false);
    

    请记住,第三个参数 (false) 的值必须与添加事件侦听器的值相同。

    然而,问题本身又引出了另一个问题:为什么?

    使用.addEventListener() 而不是更简单的.onsomething() 方法有两个原因:

    首先,它允许添加多个事件监听器。当有选择地删除它们时,这会成为一个问题:您最终可能会命名它们。如果您想将它们全部删除,那么@tidy-giant 的outerHTML 解决方案非常棒。

    其次,您确实可以选择捕获而不是冒泡事件。

    如果两个原因都不重要,您可能会决定使用更简单的onsomething 方法。

    【讨论】:

    • 喜欢这个解决方案我会使用它。不知道它是否重要,但之后仍然会有对该函数的引用,例如调用 element.fn() 仍将返回函数的结果。如果不清理,这可能是内存问题吗?
    【解决方案5】:

    您可以尝试覆盖 element.addEventListener 并做任何您想做的事情。
    类似:

    var orig = element.addEventListener;
    
    element.addEventListener = function (type, listener) {
        if (/dontwant/.test(listener.toSource())) { // listener has something i dont want
            // do nothing
        } else {
            orig.apply(this, Array.prototype.slice.apply(arguments));
        }
    };
    

    ps.:不推荐,但它会解决问题(尚未测试)

    【讨论】:

    • 您也可以替换EventTarget.prototype.addEventListener。这对我有用
    【解决方案6】:

    用文字函数分配事件处理程序是棘手的——不仅没有办法删除它们,没有克隆节点并用克隆替换它——你还可以无意中多次分配同一个处理程序,如果您使用对处理程序的引用。两个函数总是被视为两个不同的对象,即使它们的字符相同。

    【讨论】:

    • “你不能”总结一下?这是我认为正确的答案。
    • 您可以,如果您将它们分配为属性,而不是使用 addEventListener。 element.onmouseover=function(){dothis}; element.onmouseover='';
    • 在 Greasemonkey 应用程序中,我们无法控制如何在基本页面中创建事件。仅供参考,在 GM 脚本中,由于沙盒保护,element.onmouseover=function 之类的东西无论如何都不起作用。见commons.oreilly.com/wiki/index.php/Greasemonkey_Hacks/…
    【解决方案7】:

    编辑:正如Manngo 建议的每条评论,您应该使用 .off() 而不是 .unbind() 作为 .unbind() 自 jQuery 3.0 起已弃用,自 jQuery 1.7 起已被取代。

    尽管这是一个老问题而且它没有提到 jQuery,但我还是会在这里发布我的答案,因为它是搜索项 'jquery remove anonymous event handler' 的第一个结果。

    您可以尝试使用.off() 函数将其删除。

    $('#button1').click(function() {
           alert('This is a test');
    });
    
    $('#btnRemoveListener').click(function() {
           $('#button1').off('click');
    });
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
    <button id="button1">Click me</button>
    <hr/>
    <button id="btnRemoveListener">Remove listener</button>

    但这仅在您使用 jQuery 添加侦听器时才有效 - 而不是 .addEventListener

    找到这个here

    【讨论】:

    • 回到问题,jQuery其实存储了一个函数的引用,然后添加函数。这就是为什么您不需要指定要删除的 which 函数。也就是说,它在添加时不是匿名的。顺便说一句,jQuery 更喜欢 .off().unbind()
    • 为什么对一个 JS 问题给出 jquery 答案?
    【解决方案8】:

    如果你使用 jQuery,试试off 方法

    $("element").off("event");
    

    【讨论】:

      【解决方案9】:

      Jquery .off() 方法删除使用 .on() 附加的事件处理程序

      【讨论】:

        【解决方案10】:

        使用 ECMAScript2015 (ES2015, ES6) 语言规范,可以使用 nameAndSelfBind 函数将匿名回调神奇地转换为命名回调,甚至将其主体绑定到自身,从而允许事件侦听器将自己从范围内以及要从外部范围中删除 (JSFiddle):

        (function()
        {
          // an optional constant to store references to all named and bound functions:
          const arrayOfFormerlyAnonymousFunctions = [],
                removeEventListenerAfterDelay = 3000; // an auxiliary variable for setTimeout
        
          // this function both names argument function and makes it self-aware,
          // binding it to itself; useful e.g. for event listeners which then will be able
          // self-remove from within an anonymous functions they use as callbacks:
          function nameAndSelfBind(functionToNameAndSelfBind,
                                   name = 'namedAndBoundFunction', // optional
                                   outerScopeReference)            // optional
          {
            const functionAsObject = {
                                        [name]()
                                        {
                                          return binder(...arguments);
                                        }
                                     },
                  namedAndBoundFunction = functionAsObject[name];
        
            // if no arbitrary-naming functionality is required, then the constants above are
            // not needed, and the following function should be just "var namedAndBoundFunction = ":
            var binder = function() 
            { 
              return functionToNameAndSelfBind.bind(namedAndBoundFunction, ...arguments)();
            }
        
            // this optional functionality allows to assign the function to a outer scope variable
            // if can not be done otherwise; useful for example for the ability to remove event
            // listeners from the outer scope:
            if (typeof outerScopeReference !== 'undefined')
            {
              if (outerScopeReference instanceof Array)
              {
                outerScopeReference.push(namedAndBoundFunction);
              }
              else
              {
                outerScopeReference = namedAndBoundFunction;
              }
            }
            return namedAndBoundFunction;
          }
        
          // removeEventListener callback can not remove the listener if the callback is an anonymous
          // function, but thanks to the nameAndSelfBind function it is now possible; this listener
          // removes itself right after the first time being triggered:
          document.addEventListener("visibilitychange", nameAndSelfBind(function(e)
          {
            e.target.removeEventListener('visibilitychange', this, false);
            console.log('\nEvent listener 1 triggered:', e, '\nthis: ', this,
                        '\n\nremoveEventListener 1 was called; if "this" value was correct, "'
                        + e.type + '"" event will not listened to any more');
          }, undefined, arrayOfFormerlyAnonymousFunctions), false);
        
          // to prove that deanonymized functions -- even when they have the same 'namedAndBoundFunction'
          // name -- belong to different scopes and hence removing one does not mean removing another,
          // a different event listener is added:
          document.addEventListener("visibilitychange", nameAndSelfBind(function(e)
          {
            console.log('\nEvent listener 2 triggered:', e, '\nthis: ', this);
          }, undefined, arrayOfFormerlyAnonymousFunctions), false);
        
          // to check that arrayOfFormerlyAnonymousFunctions constant does keep a valid reference to
          // formerly anonymous callback function of one of the event listeners, an attempt to remove
          // it is made:
          setTimeout(function(delay)
          {
            document.removeEventListener('visibilitychange',
                     arrayOfFormerlyAnonymousFunctions[arrayOfFormerlyAnonymousFunctions.length - 1],
                     false);
            console.log('\nAfter ' + delay + 'ms, an event listener 2 was removed;  if reference in '
                        + 'arrayOfFormerlyAnonymousFunctions value was correct, the event will not '
                        + 'be listened to any more', arrayOfFormerlyAnonymousFunctions);
          }, removeEventListenerAfterDelay, removeEventListenerAfterDelay);
        })();
        

        【讨论】:

          【解决方案11】:
          //get Event
          let obj = window; //for example
          let eventStr= "blur"; //for example
          let index= 0; //you can console.log(getEventListeners(obj)[eventStr]) and check index
          let e = getEventListeners(obj)[eventStr][index];
          //remove this event
          obj .removeEventListener(eventStr,e.listener,e.useCapture);
          

          结束 :) 我在 chrome 92 中测试,工作正常

          【讨论】:

            【解决方案12】:

            我如何为我的 customEvent 使用 options 参数

            options Optional
            An object that specifies characteristics about the event listener. The available options are:
            ...
            **once**
            A boolean value indicating that the listener should be invoked at most once after being added. If true, the listener would be automatically removed when invoked.
            

            对于我创建的自定义函数,它运行得非常好。

            const addItemOpenEventListener = (item, openItem) => {
              document.addEventListener('order:open', ({detail}) => {
                if(detail.id === item.id) {
                  openItem();
                }
              }, {once: true})
            };
            
            el.addItemOpenEventListener(item, () => dispatch(itemOpen)()));
            

            检查了我的控制台,似乎可以正常工作(感谢任何反馈!)

            【讨论】:

              【解决方案13】:

              以下内容对我来说已经足够好了。该代码处理另一个事件触发侦听器从元素中删除的情况。无需事先声明函数。

              myElem.addEventListener("click", myFunc = function() { /*do stuff*/ });
              
              /*things happen*/
              
              myElem.removeEventListener("click", myFunc);
              

              【讨论】:

              • 你违反了问题的限制条件。
              猜你喜欢
              • 1970-01-01
              • 2013-06-27
              • 1970-01-01
              • 1970-01-01
              • 2010-10-10
              • 1970-01-01
              • 2018-09-04
              • 1970-01-01
              • 1970-01-01
              相关资源
              最近更新 更多