不知道函数的情况下如何使用removeEventListener

42

一些第三方插件会将eventListener附加到网站中。如何在不知道附加的函数的情况下删除eventListener

我参考了removeEventListener,但是我无法得到删除它的线索。

例如:getEventListeners(window)显示已附加的事件。但是,如果我尝试使用window.removeEventListener("eventname")来删除事件,除非我知道该函数,否则它无法正常工作。

请帮忙解答,提前感谢。


请参阅与此相关问题的不同答案(我也发布了一个答案):https://dev59.com/WG855IYBdhLWcg3wXTAI - baptx
4个回答

29

getEventListeners(window) 将返回一个包含事件及其已注册事件监听器的映射表。

例如,对于 DOMContentLoaded 事件,您可以有多个事件监听器。如果您知道要删除的监听器的索引(或仅存在一个),则可以执行以下操作:

var eventlistener = getEventListeners(window)["DOMContentLoaded"][index];
window.removeEventListener("DOMContentLoaded", 
                           eventlistener.listener,
                           eventlistener.useCapture);

2
更方便的是,它还返回了取消注册函数 removegetEventListeners(window).DOMContentLoaded[0].remove() - dfsq
3
@dfsq,可以在Chrome中运行,但不能在Firefox中运行。(无法测试IE)。 - manji
22
@Dineshkani这不是每个浏览器都实现的,也不是规范的一部分。除非你的问题只针对Chrome,否则不应该接受这个答案。在这种情况下,应该在问题中说明。 - plalx
2
@Dineshkani 嗯,这会让其他查看此问题的人感到困惑。正确答案已经由jAndy在下面给出了。 - plalx
火狐浏览器中没有这个方法。这不应该是一个可接受的解决方案。 - ADTC
显示剩余6条评论

14

很遗憾,您不能这样做。您需要有事件处理程序函数的引用才能通过 removeEventListener 来移除它。

如果您无法获得该引用,则唯一的选择是完全替换该 Node


jAndy,有没有办法通过jQuery或JavaScript获取该引用?因为该事件是由第三方添加的,并且该事件附加在窗口元素上。 - Dineshkani
据我所知,目前还没有(但希望有些高手能在这里纠正我)。通过addEventListener添加的本地事件不会存储在JavaScript可访问的任何位置。 - jAndy
感谢您的回复,@jAndy。 - Dineshkani
3
使用 getEventListeners 是可以实现的,因为它存储着事件监听函数。 - dfsq
我想补充一点,不能这样做使得该API非常出色。想象一下,如果某个可怕的库可以破坏掉你的所有监听器会怎么样? - doug65536
显示剩余3条评论

0
注意事项:使用特定于浏览器的getEventListeners,仅适用于Chrome和Edge浏览器。
如果您需要删除所有事件监听器:
// selector is optional - defaults to all elements including window and document
// Do not pass window / document objects. Instead use pseudoselectors: 'window' or 'document'
// eTypeArray is optional - defaults to clearing all event types
function removeAllEventListeners(selector = '*', eTypeArray = ['*']) {
  switch (selector.toLowerCase()) {
    case 'window':
      removeListenersFromElem(window);
      break;
    case 'document':
      removeListenersFromElem(document);
      break;
    case '*':
      removeListenersFromElem(window);
      removeListenersFromElem(document);
    default:
      document.querySelectorAll(selector).forEach(removeListenersFromElem);
  }
  
  function removeListenersFromElem(elem) {
    let eListeners = getEventListeners(elem);
    let eTypes = Object.keys(eListeners);
    for (let eType of inBoth(eTypes, eTypeArray)) {
      eListeners[eType].forEach((eListener)=>{
        let options = {};
        inBoth(Object.keys(eListener), ['capture', 'once', 'passive', 'signal'])
          .forEach((key)=>{ options[key] = eListener[key] });
        elem.removeEventListener(eType, eListener.listener, eListener.useCapture);
        elem.removeEventListener(eType, eListener.listener, options);
      });
    }
  }

  function inBoth(arrA, arrB) {
    setB = new Set(arrB);
    if (setB.has('*')) {
      return arrA;
    } else {
      return arrA.filter(a => setB.has(a));
    }
  }
}

使用:

removeAllEventListeners('a.fancyLink'); // remove all event types
removeAllEventListeners('a.fancyLink', ['click', 'hover']); // remove these types
removeAllEventListeners('*', ['click', 'hover']); // remove these types everywhere
removeAllEventListeners(); // remove everything you can

注意,这种方法并不总是有效。根据MDN的说法:
值得注意的是,某些浏览器版本在这方面存在不一致性,除非有特殊原因,否则在调用removeEventListener()时,最好使用与调用addEventListener()时相同的值。
我的options的使用尝试通过希望使用添加监听器时相同的值来处理这个问题,从而调用removeEventListener

-1

更新:2023年

在现代浏览器中,可以在不知道实际函数引用的情况下删除EventListeners。

使用AbortController来移除事件。使用AbortSignal,您可以简单地获取信号来为您删除它:

示例代码:

const controller = new AbortController();
const { signal } = controller;

window.addEventListener('resize', () => doSomething(), { signal });

controller.abort(); // It wll remove the "resize" event handler.

您可以检查并添加一个旧浏览器的polyfill

2
这将删除您刚添加的事件监听器。但是只有那一个,所以它只适用于您首先添加事件监听器的情况。但如果您正在添加事件侦听器,那么最好保留对函数的引用并进行常规删除。 - AntonOfTheWoods

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