Javascript/DOM:如何删除DOM对象的所有事件?

Flo*_*ler 73 javascript events dom

只是提问:有没有办法彻底删除对象的所有事件,例如div?

编辑:我正在添加div.addEventListener('click',eventReturner(),false);一个事件.

function eventReturner() {
    return function() {
        dosomething();
    };
}
Run Code Online (Sandbox Code Playgroud)

EDIT2:我找到了一种方法,但是不能用于我的情况:

var returnedFunction;
function addit() {
    var div = document.getElementById('div');
    returnedFunction = eventReturner();
    div.addEventListener('click',returnedFunction,false); //You HAVE to take here a var and not the direct call to eventReturner(), because the function address must be the same, and it would change, if the function was called again.
}
function removeit() {
    var div = document.getElementById('div');
    div.removeEventListener('click',returnedFunction,false);
}
Run Code Online (Sandbox Code Playgroud)

Fel*_*ing 88

我不确定你删除所有事件的意思.删除特定类型事件的所有处理程序或一种类型的所有事件处理程序?

删除所有事件处理程序

如果要删除所有事件处理程序(任何类型),可以克隆该元素并将其替换为其克隆:

var clone = element.cloneNode(true);
Run Code Online (Sandbox Code Playgroud)

注意:这将保留属性和子项,但不会保留对DOM属性的任何更改.


删除特定类型的"匿名"事件处理程序

另一种方法是使用,removeEventListener()但我想你已经尝试过这个并没有用.这是一个问题:

调用addEventListener匿名函数每次都会创建一个新的侦听器.调用removeEventListener匿名函数无效.匿名函数每次调用时都会创建一个唯一的对象,它不是对现有对象的引用,尽管它可以调用一个对象.以这种方式添加事件侦听器时,请确保它只添加一次,它是永久的(无法删除),直到它被添加到的对象被销毁.

您实际上是将一个匿名函数传递给addEventListeneras eventReturner返回一个函数.

你必须有可能解决这个问题:

  1. 不要使用返回函数的函数.直接使用该功能:

    function handler() {
        dosomething();
    }
    
    div.addEventListener('click',handler,false);
    
    Run Code Online (Sandbox Code Playgroud)
  2. 创建一个包装器,用于addEventListener存储对返回函数的引用并创建一些奇怪的removeAllEvents函数:

    var _eventHandlers = {}; // somewhere global
    
    function addListener(node, event, handler, capture) {
        if(!(node in _eventHandlers)) {
            // _eventHandlers stores references to nodes
            _eventHandlers[node] = {};
        }
        if(!(event in _eventHandlers[node])) {
            // each entry contains another entry for each event type
            _eventHandlers[node][event] = [];
        }
        // capture reference
        _eventHandlers[node][event].push([handler, capture]);
        node.addEventListener(event, handler, capture);
     }
    
    function removeAllListeners(node, event) {
        if(node in _eventHandlers) {
            var handlers = _eventHandlers[node];
            if(event in handlers) {
                var eventHandlers = handlers[event];
                for(var i = eventHandlers.length; i--;) {
                    var handler = eventHandlers[i];
                    node.removeEventListener(event, handler[0], handler[1]);
                }
            }
        }
    }
    
    Run Code Online (Sandbox Code Playgroud)

    然后你可以用它:

    addListener(div, 'click', eventReturner(), false)
    // and later
    removeListeners(div, 'click')
    
    Run Code Online (Sandbox Code Playgroud)

DEMO

注意:如果您的代码运行了很长时间并且您正在创建并删除大量元素,则必须确保在_eventHandlers销毁它们时删除包含的元素.

  • `var 克隆 = element.cloneNode(true); 元素.replaceWith(克隆);` (5认同)
  • 您是否尝试过使用多个 div 元素进行此操作?节点 var 将实际转换为字符串,例如 '[object HTMLDivElement]' 这意味着您最终将所有内容添加到同一个节点。 (2认同)

小智 25

使用事件监听器自己的功能remove().例如:

getEventListeners().click.forEach((e)=>{e.remove()})
Run Code Online (Sandbox Code Playgroud)

  • 似乎`getEventListeners`仅在WebKit开发工具和FireBug中可用.不是你可以在你的代码中调用的东西. (30认同)
  • 实际上仅在 Chrome 中支持。由于这不是跨浏览器,因此它是一个糟糕的解决方案。 (7认同)
  • 这似乎只适用于chrome*console*.即使在页面上的脚本上它也不起作用. (6认同)
  • `getEventListeners(document).click.forEach((e)=>{e.remove()})` 产生这个错误:`VM214:1 Uncaught TypeError: e.remove is not a function` (5认同)
  • 不知道为什么这不是正确的答案.问题在SO上出现了很多次,并且可能使用克隆方法解决问题. (2认同)

pab*_*mbs 24

这将从子节点中删除所有侦听器,但对于大页面来说会很慢.写得非常简单.

element.outerHTML = element.outerHTML;
Run Code Online (Sandbox Code Playgroud)

  • @Ryan 而不是 `document.querySelector('body').outerHTML` 你可以只输入 `document.body.outerHTML` (3认同)
  • 好答案。对于叶节点,这似乎是最好的主意。 (2认同)
  • `document.querySelector('body')。outerHTML = document.querySelector('body')。outerHTML`为我工作。 (2认同)

Ada*_*atz 10

克隆该元素并用其克隆替换该元素。事件不会被克隆。

\n
elem.replaceWith(elem.cloneNode(true));\n
Run Code Online (Sandbox Code Playgroud)\n

这使用Node.cloneNode()来克隆elemDOM 对象,该对象会忽略所有事件处理程序(不过,正如Jan Turo\xc5\x88\ 的回答所述,类似的属性onclick="\xe2\x80\xa6"将保留)。然后它使用Element.replaceWith()替换elem该克隆。简单地分配给匿名克隆对我来说不起作用。

\n

elem.outerHTML这应该比重新定义自身更快更干净(如pabombs的答案所建议的),但可能比迭代并清除每个侦听器的答案慢(注意这getEventListeners()似乎只在Chrome的开发控制台\xe2\x80中可用) \x94在 Chrome 的其他地方没有,在 Firefox 上根本没有)。据推测,在需要清除的听众数量较大时,这种非循环解决方案会变得更快。

\n

(这是在asheroto 的评论的帮助下对Felix Kling 的答案的简化。)

\n


Jma*_*kuc 9

正如corwin.amber所说,Webkit和其他人之间存在差异.

在Chrome中:

getEventListeners(document);
Run Code Online (Sandbox Code Playgroud)

这为您提供了一个包含所有现有事件监听器的对象:

Object 
 click: Array[1]
 closePopups: Array[1]
 keyup: Array[1]
 mouseout: Array[1]
 mouseover: Array[1]
 ...
Run Code Online (Sandbox Code Playgroud)

在这里,您可以访问要删除的侦听器:

getEventListeners(document).copy[0].remove();
Run Code Online (Sandbox Code Playgroud)

所以所有的事件监听器:

for(var eventType in getEventListeners(document)) {
   getEventListeners(document)[eventType].forEach(
      function(o) { o.remove(); }
   ) 
}
Run Code Online (Sandbox Code Playgroud)

在Firefox中

有点不同,因为它使用不包含删除函数的侦听器包装器.您必须获取要删除的侦听器:

document.removeEventListener("copy", getEventListeners(document).copy[0].listener)
Run Code Online (Sandbox Code Playgroud)

所有事件监听器:

for(var eventType in getEventListeners(document)) {
  getEventListeners(document)[eventType].forEach(
    function(o) { document.removeEventListener(eventType, o.listener) }
  ) 
}
Run Code Online (Sandbox Code Playgroud)

我偶然发现这篇文章试图禁用新闻网站的烦人复制保护.

请享用!

  • Firefox 告诉我没有定义`getEventListeners`? (6认同)
  • 这是一个糟糕的解决方案,因为目前 getEventListeners 仅受 Chrome 支持。 (3认同)

Joh*_*kel 6

您可以添加一个钩子函数来拦截所有对addEventHandler. 该钩子会将处理程序推送到可用于清理的列表。例如,

if (EventTarget.prototype.original_addEventListener == null) {
    EventTarget.prototype.original_addEventListener = EventTarget.prototype.addEventListener;

    function addEventListener_hook(typ, fn, opt) {
        console.log('--- add event listener',this.nodeName,typ);
        this.all_handlers = this.all_handlers || [];
        this.all_handlers.push({typ,fn,opt});
        this.original_addEventListener(typ, fn, opt);  
    }

    EventTarget.prototype.addEventListener = addEventListener_hook;
}
Run Code Online (Sandbox Code Playgroud)

您应该将此代码插入到主网页顶部附近(例如index.html)。在清理期间,您可以循环遍历 all_handlers,并为每个处理程序调用removeEventHandler。不必担心使用同一函数多次调用removeEventHandler。它是无害的。

例如,

function cleanup(elem) {
    for (let t in elem) if (t.startsWith('on') && elem[t] != null) {
        elem[t] = null;
        console.log('cleanup removed listener from '+elem.nodeName,t);
    } 
    for (let t of elem.all_handlers || []) {
        elem.removeEventListener(t.typ, t.fn, t.opt);
        console.log('cleanup removed listener from '+elem.nodeName,t.typ);
    } 
}
Run Code Online (Sandbox Code Playgroud)

注意:对于 IE,请使用 Element 而不是 EventTarget,并将 => 更改为 function 以及其他各种内容。


hos*_*ian 5

您可以添加功能并通过分配它们来删除所有其他点击

btn1 = document.querySelector(".btn-1")
btn1.addEventListener("click" , _=>{console.log("hello")})
btn1.addEventListener("click" , _=>{console.log("How Are you ?")})

btn2 = document.querySelector(".btn-2")
btn2.onclick = _=>{console.log("Hello")}
btn2.onclick = _=>{console.log("Bye")}
Run Code Online (Sandbox Code Playgroud)
<button class="btn-1">Hello to Me</button>
<button class="btn-2">Hello to Bye</button>
Run Code Online (Sandbox Code Playgroud)