Javascript/DOM:如何删除 DOM 对象的所有事件?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/4386300/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Javascript/DOM: How to remove all events of a DOM object?
提问by Florian Müller
Just question: Is there any way to completely remove all events of an object, e.g. a div?
只是问题:有没有办法完全删除一个对象的所有事件,例如一个div?
EDIT: I'm adding per div.addEventListener('click',eventReturner(),false);
an event.
编辑:我正在添加每个div.addEventListener('click',eventReturner(),false);
事件。
function eventReturner() {
return function() {
dosomething();
};
}
EDIT2: I found a way, which is working, but not possible to use for my case:
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);
}
回答by Felix Kling
I am not sure what you mean with remove allevents. Remove all handlers for a specific type of event or all event handlers for one type?
我不确定您的意思是删除所有事件。删除特定类型事件的所有处理程序还是删除一种类型的所有事件处理程序?
Remove all event handlers
删除所有事件处理程序
If you want to remove all event handlers (of any type), you could clonethe element and replace it with its clone:
如果要删除所有事件处理程序(任何类型),您可以克隆该元素并将其替换为它的克隆:
var clone = element.cloneNode(true);
Note:This will preserve attributes and children, but it will not preserve any changes to DOM properties.
注意:这将保留属性和子项,但不会保留对 DOM 属性的任何更改。
Remove "anonymous" event handlers of specific type
删除特定类型的“匿名”事件处理程序
The other way is to use removeEventListener()
but I guess you already tried this and it didn't work. Here is the catch:
另一种方法是使用,removeEventListener()
但我猜你已经尝试过这个,但没有用。这是捕获:
Calling
addEventListener
to an anonymous function creates a new listener each time. CallingremoveEventListener
to an anonymous function has no effect. An anonymous function creates a unique object each time it is called, it is not a reference to an existing object though it may call one. When adding an event listener in this manner be sure it is added only once, it is permanent (cannot be removed) until the object it was added to, is destroyed.
addEventListener
每次调用匿名函数都会创建一个新的侦听器。调用removeEventListener
匿名函数无效。匿名函数每次被调用时都会创建一个唯一的对象,尽管它可以调用一个对象,但它不是对现有对象的引用。以这种方式添加事件侦听器时,请确保它只添加一次,它是永久性的(不能删除),直到它被添加到的对象被销毁。
You are essentially passing an anonymous function to addEventListener
as eventReturner
returns a function.
您本质上是将匿名函数传递给addEventListener
作为eventReturner
返回函数。
You have two possibilities to solve this:
你有两种可能来解决这个问题:
Don't use a function that returns a function. Use the function directly:
function handler() { dosomething(); } div.addEventListener('click',handler,false);
Create a wrapper for
addEventListener
that stores a reference to the returned function and create some weirdremoveAllEvents
function:var _eventHandlers = {}; // somewhere global const addListener = (node, event, handler, capture = false) => { if (!(event in _eventHandlers)) { _eventHandlers[event] = [] } // here we track the events and their nodes (note that we cannot // use node as Object keys, as they'd get coerced into a string _eventHandlers[event].push({ node: node, handler: handler, capture: capture }) node.addEventListener(event, handler, capture) } const removeAllListeners = (targetNode, event) => { // remove listeners from the matching nodes _eventHandlers[event] .filter(({ node }) => node === targetNode) .forEach(({ node, handler, capture }) => node.removeEventListener(event, handler, capture)) // update _eventHandlers global _eventHandlers[event] = _eventHandlers[event].filter( ({ node }) => node !== targetNode, ) }
And then you could use it with:
addListener(div, 'click', eventReturner(), false) // and later removeAllListeners(div, 'click')
不要使用返回函数的函数。直接使用函数:
function handler() { dosomething(); } div.addEventListener('click',handler,false);
创建一个包装器,用于
addEventListener
存储对返回函数的引用并创建一些奇怪的removeAllEvents
函数:var _eventHandlers = {}; // somewhere global const addListener = (node, event, handler, capture = false) => { if (!(event in _eventHandlers)) { _eventHandlers[event] = [] } // here we track the events and their nodes (note that we cannot // use node as Object keys, as they'd get coerced into a string _eventHandlers[event].push({ node: node, handler: handler, capture: capture }) node.addEventListener(event, handler, capture) } const removeAllListeners = (targetNode, event) => { // remove listeners from the matching nodes _eventHandlers[event] .filter(({ node }) => node === targetNode) .forEach(({ node, handler, capture }) => node.removeEventListener(event, handler, capture)) // update _eventHandlers global _eventHandlers[event] = _eventHandlers[event].filter( ({ node }) => node !== targetNode, ) }
然后你可以使用它:
addListener(div, 'click', eventReturner(), false) // and later removeAllListeners(div, 'click')
Note:If your code runs for a long time and you are creating and removing a lot of elements, you would have to make sure to remove the elements contained in _eventHandlers
when you destroy them.
注意:如果您的代码运行了很长时间并且您正在创建和删除大量元素,则必须确保在_eventHandlers
销毁它们时删除其中包含的元素。
回答by pabombs
This will remove all listeners from children but will be slow for large pages. Brutally simple to write.
这将从子级中删除所有侦听器,但对于大页面来说会很慢。写起来非常简单。
element.outerHTML = element.outerHTML;
回答by JuanGG
Use the event listener's own function remove()
. For example:
使用事件监听器自己的函数remove()
。例如:
getEventListeners().click.forEach((e)=>{e.remove()})
回答by Jmakuc
As corwin.amber says, there are differences between Webkit an others.
正如 corwin.amber 所说,Webkit 与其他 Webkit 之间存在差异。
In Chrome:
在 Chrome 中:
getEventListeners(document);
Which gives you an Object with all the existing event listeners:
这为您提供了一个包含所有现有事件侦听器的对象:
Object
click: Array[1]
closePopups: Array[1]
keyup: Array[1]
mouseout: Array[1]
mouseover: Array[1]
...
From here you can reach the listener you want to remove:
从这里您可以访问要删除的侦听器:
getEventListeners(document).copy[0].remove();
So All the event listeners:
所以所有的事件监听器:
for(var eventType in getEventListeners(document)) {
getEventListeners(document)[eventType].forEach(
function(o) { o.remove(); }
)
}
In Firefox
在火狐浏览器中
Is a little bit different because it uses a listener wrapper that contains no remove function. You have to get the listener you want to remove:
有点不同,因为它使用不包含删除函数的侦听器包装器。您必须获得要删除的侦听器:
document.removeEventListener("copy", getEventListeners(document).copy[0].listener)
All the event listeners:
所有事件侦听器:
for(var eventType in getEventListeners(document)) {
getEventListeners(document)[eventType].forEach(
function(o) { document.removeEventListener(eventType, o.listener) }
)
}
I stumbled with this post trying to disable the annoying copy protection of a news website.
我偶然发现了这篇试图禁用新闻网站令人讨厌的复制保护的帖子。
Enjoy!
享受!
回答by baptx
To complete the answers, here are real-world examples of removing events when you are visiting websites and don't have control over the HTML and JavaScript code generated.
为了完成答案,以下是在您访问网站并且无法控制生成的 HTML 和 JavaScript 代码时删除事件的真实示例。
Some annoying websites are preventing you to copy-paste usernames on login forms, which could easily be bypassed if the onpaste
event was added with the onpaste="return false"
HTML attribute.
In this case we just need to right click on the input field, select "Inspect element" in a browser like Firefox and remove the HTML attribute.
一些烦人的网站阻止您在登录表单上复制粘贴用户名,如果onpaste
使用onpaste="return false"
HTML 属性添加事件,则可以轻松绕过。在这种情况下,我们只需要右键单击输入字段,在 Firefox 等浏览器中选择“检查元素”并删除 HTML 属性。
However, if the event was added through JavaScript like this:
但是,如果事件是通过 JavaScript 添加的,如下所示:
document.getElementById("lyca_login_mobile_no").onpaste = function(){return false};
We will have to remove the event through JavaScript also:
我们还必须通过 JavaScript 删除该事件:
document.getElementById("lyca_login_mobile_no").onpaste = null;
In my example, I used the ID "lyca_login_mobile_no" since it was the text input ID used by the website I was visiting.
在我的示例中,我使用了 ID“lyca_login_mobile_no”,因为它是我访问的网站使用的文本输入 ID。
Another way to remove the event (which will also remove all the events) is to remove the node and create a new one, like we have to do if addEventListener
was used to add events using an anonymous function that we cannot remove with removeEventListener
.
This can also be done through the browser console by inspecting an element, copying the HTML code, removing the HTML code and then pasting the HTML code at the same place.
删除事件的另一种方法(也将删除所有事件)是删除节点并创建一个新节点,就像我们必须做的 ifaddEventListener
用于使用匿名函数添加事件,而我们无法使用removeEventListener
. 这也可以通过浏览器控制台通过检查元素、复制 HTML 代码、删除 HTML 代码然后将 HTML 代码粘贴到同一位置来完成。
It can also be done faster and automated through JavaScript:
它也可以通过 JavaScript 更快地完成并自动化:
var oldNode = document.getElementById("lyca_login_mobile_no");
var newNode = oldNode.cloneNode(true);
oldNode.parentNode.insertBefore(newNode, oldNode);
oldNode.parentNode.removeChild(oldNode);
Update: if the web app is made using a JavaScript framework like Angular, it looks the previous solutions are not working or breaking the app. Another workaround to allow pasting would be to set the value through JavaScript:
更新:如果网络应用程序是使用像 Angular 这样的 JavaScript 框架制作的,看起来以前的解决方案不起作用或破坏了应用程序。允许粘贴的另一种解决方法是通过 JavaScript 设置值:
document.getElementById("lyca_login_mobile_no").value = "username";
At the moment, I don't know if there is a way to remove all form validation and restriction events without breaking an app written entirely in JavaScript like Angular.
目前,我不知道是否有一种方法可以在不破坏像 Angular 这样完全用 JavaScript 编写的应用程序的情况下删除所有表单验证和限制事件。
回答by Filipe Melo
Chrome only
仅铬
As I'm trying to remove an EventListener within a Protractor test and do not have access to the Listener in the test, the following works to remove all event listeners of a single type:
由于我正在尝试删除量角器测试中的 EventListener 并且无法访问测试中的 Listener,因此以下操作可以删除单一类型的所有事件侦听器:
function(eventType){
getEventListeners(window).[eventType].forEach(
function(e){
window.removeEventListener(eventType, e.listener)
}
);
}
I hope this helps someone as previous answer were using the "remove" method which since then does not work anymore.
我希望这对某人有所帮助,因为之前的答案使用的是“删除”方法,此后该方法不再有效。
回答by feyzullah y?ld?z
angular has a polyfill for this issue, you can check. I did not understand much but maybe it can help.
angular 有针对此问题的 polyfill,您可以查看。我不太明白,但也许它可以帮助。
const REMOVE_ALL_LISTENERS_EVENT_LISTENER = 'removeAllListeners';
const REMOVE_ALL_LISTENERS_EVENT_LISTENER = 'removeAllListeners';
proto[REMOVE_ALL_LISTENERS_EVENT_LISTENER] = function () {
const target = this || _global;
const eventName = arguments[0];
if (!eventName) {
const keys = Object.keys(target);
for (let i = 0; i < keys.length; i++) {
const prop = keys[i];
const match = EVENT_NAME_SYMBOL_REGX.exec(prop);
let evtName = match && match[1];
// in nodejs EventEmitter, removeListener event is
// used for monitoring the removeListener call,
// so just keep removeListener eventListener until
// all other eventListeners are removed
if (evtName && evtName !== 'removeListener') {
this[REMOVE_ALL_LISTENERS_EVENT_LISTENER].call(this, evtName);
}
}
// remove removeListener listener finally
this[REMOVE_ALL_LISTENERS_EVENT_LISTENER].call(this, 'removeListener');
}
else {
const symbolEventNames = zoneSymbolEventNames[eventName];
if (symbolEventNames) {
const symbolEventName = symbolEventNames[FALSE_STR];
const symbolCaptureEventName = symbolEventNames[TRUE_STR];
const tasks = target[symbolEventName];
const captureTasks = target[symbolCaptureEventName];
if (tasks) {
const removeTasks = tasks.slice();
for (let i = 0; i < removeTasks.length; i++) {
const task = removeTasks[i];
let delegate = task.originalDelegate ? task.originalDelegate : task.callback;
this[REMOVE_EVENT_LISTENER].call(this, eventName, delegate, task.options);
}
}
if (captureTasks) {
const removeTasks = captureTasks.slice();
for (let i = 0; i < removeTasks.length; i++) {
const task = removeTasks[i];
let delegate = task.originalDelegate ? task.originalDelegate : task.callback;
this[REMOVE_EVENT_LISTENER].call(this, eventName, delegate, task.options);
}
}
}
}
if (returnTarget) {
return this;
}
};
....
....
回答by Rafal Enden
You could add another event listener and call preventDefault()
to stop propagation of the previous listeners.
您可以添加另一个事件侦听器并调用preventDefault()
以停止先前侦听器的传播。
document.querySelectorAll('a.my-link').forEach((el) => {
el.addEventListener('click', (ev) => {
ev.preventDefault()
})
})
回答by Lacho Tomov
One method is to add a new event listener that calls e.stopImmediatePropagation().
一种方法是添加一个调用 e.stopImmediatePropagation() 的新事件侦听器。
回答by Ionu? Staicu
var div = getElementsByTagName('div')[0]; /* first div found; you can use getElementById for more specific element */
div.onclick = null; // OR:
div.onclick = function(){};
//edit
//编辑
I didn't knew what method are you using for attaching events. For addEventListener
you can use this:
我不知道您使用什么方法来附加事件。因为addEventListener
你可以使用这个:
div.removeEventListener('click',functionName,false); // functionName is the name of your callback function