请问JS中如何移除所有的点击事件监听函数?

请问JS中如何移除所有的点击事件监听函数?或者怎样获取其监听函数的引用(那样就可以手动移除)?

(对于任意元素,我并不知道它注册了哪些点击回调,并且回调并不是咱注册的,所以装饰addEventListener等函数并不能奏效)

阅读 19.7k
5 个回答

首先你要确定要屏蔽的是否与库和框架有关。如果是库或框架绑定的事件,可以劫持框架的处理逻辑修改。
下面说的是原生部分。

方案一

使用 CSS

* { `pointer-events: none !important; }

缺点

  • 所有的指针事件都不起效果了;
  • 如果style里指定了规则,CSS的规则无法覆盖

方案二

在捕获阶段阻止事件

document
  .querySelectorAll("*")
  .forEach(node =>
    node.addEventListener(
      "click",
      event => event.stopImmediatePropagation(),
      true
    )
  );

方案三

劫持addEventListener函数。这个不细说了。这个方案需要劫持发生在注册之前,所以要在第一个同步script执行之前。条件比较苛刻。

方案四

在整个页面上覆盖一层div。因为div无法被点穿,所以可以屏蔽所有指针事件。
在这个基础上,为div增加事件绑定,当事件发生时,可以获取发生事件的指针坐标。利用指针坐标进而获取页面上的元素 document.elementFromPoint,然后手动模拟触发事件 dispatchEvent
这个方法适用于为元素添加有限的事件绑定白名单,但无法枚举所有已绑定的事件。

提供一个思路,
在 script 内增加代码, 或者 window.onload
把 addEventListener 改造一下,添加事件的时候自动注册到 window 的属性
然后你懂的 ... 基本搞定监听和移除不是问题 ...
你看成不成

可以使用getEventListeners函数获取handler

getEventListeners(el).click.forEach(fn => el.removeEventListener(fn))

如果可以的话,也可以给addEventListener包一层,把handler的引用缓存起来

(() => {
  const addEventListener = Element.prototype.addEventListener
  Element.prototype.addEventListener = function (type, listener) {
    this.__listeners = this.__listeners || {}
    if (this.__listeners[type]) {
      this.__listeners[type].push(listener)
    } else {
      this.__listeners[type] = [listener]
    }
    addEventListener.call(this, type, listener)
  }
})()

el.__listeners.click.forEach(fn => el.removeEventListener('click', fn))

在客户脚本前注入一段自己的脚本,为你想要监控的原始添加对应的事件监听,然后调用stopPropagation,阻止事件冒泡

electron或puppeter可以绑定实现脚本注入

时间注册阶段完全不可控,那还真想不到什么办法。
比较粗暴的……copy一下目标dom,然后删除重建。
但是即便如此,一些委托在上层的事件依然有效。

推荐问题
宣传栏