Javascript / DOM: Wie entferne ich alle Ereignisse eines DOM-Objekts?

92

Nur Frage: Gibt es eine Möglichkeit, alle Ereignisse eines Objekts, z. B. eines Div, vollständig zu entfernen?

EDIT: Ich füge pro div.addEventListener('click',eventReturner(),false);Ereignis hinzu.

function eventReturner() {
    return function() {
        dosomething();
    };
}

EDIT2: Ich habe einen Weg gefunden, der funktioniert, aber für meinen Fall nicht verwendet werden kann:

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);
}
Florian Müller
quelle
Wie hängen Sie die Ereignisse an?
Felix Kling
2
Der Titel fragt nach den Elementen des Objekts, während die eigentliche Frage nach den Ereignissen fragt . Möchten Sie die untergeordneten Elemente oder die Ereignisse entfernen?
Pär Wieslander
oh d * mn, das war, weil ich an etwas anderes gedacht habe, als ich das schrieb ... ich kümmere mich um die Ereignisse
Florian Müller
Ich kenne den genauen Fall nicht, aber in einigen Fällen können Sie als Problemumgehung die Methoden 'on *' (als div.onclick = function) verwenden, die immer mit einem einzelnen Listener funktioniert und als einfach zu entfernen ist div.onclick=null. Natürlich sollten Sie addEventListenerin diesem Fall nicht ganz verwenden, da dadurch ein separater Listener hinzugefügt wird, der sich von dem in unterscheidet onclick.
Venimus

Antworten:

103

Ich bin nicht sicher, was Sie mit Entfernen aller Ereignisse meinen . Alle Handler für einen bestimmten Ereignistyp oder alle Ereignishandler für einen bestimmten Typ entfernen?

Entfernen Sie alle Ereignishandler

Wenn Sie alle Ereignishandler (eines beliebigen Typs) entfernen möchten, können Sie das Element klonen und durch seinen Klon ersetzen:

var clone = element.cloneNode(true);

Hinweis: Dadurch werden Attribute und untergeordnete Elemente beibehalten, Änderungen an den DOM-Eigenschaften werden jedoch nicht beibehalten.


Entfernen Sie "anonyme" Ereignishandler eines bestimmten Typs

Die andere Möglichkeit ist die Verwendung, removeEventListener()aber ich denke, Sie haben dies bereits versucht und es hat nicht funktioniert. Hier ist der Haken :

Durch Aufrufen addEventListenereiner anonymen Funktion wird jedes Mal ein neuer Listener erstellt. Das Aufrufen removeEventListenereiner anonymen Funktion hat keine Auswirkung . Eine anonyme Funktion erstellt bei jedem Aufruf ein eindeutiges Objekt. Sie verweist nicht auf ein vorhandenes Objekt, obwohl sie möglicherweise eines aufruft. Wenn Sie einen Ereignis-Listener auf diese Weise hinzufügen, stellen Sie sicher, dass er nur einmal hinzugefügt wird. Er ist permanent (kann nicht entfernt werden), bis das Objekt, zu dem er hinzugefügt wurde, zerstört wird.

Sie übergeben im Wesentlichen eine anonyme Funktion an addEventListeneras, eventReturnerum eine Funktion zurückzugeben.

Sie haben zwei Möglichkeiten, dies zu lösen:

  1. Verwenden Sie keine Funktion, die eine Funktion zurückgibt. Verwenden Sie die Funktion direkt:

    function handler() {
        dosomething();
    }
    
    div.addEventListener('click',handler,false);
  2. Erstellen Sie einen Wrapper addEventListener, in dem ein Verweis auf die zurückgegebene Funktion gespeichert wird, und erstellen Sie eine seltsame removeAllEventsFunktion:

    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,
      )
    }

    Und dann könnten Sie es verwenden mit:

    addListener(div, 'click', eventReturner(), false)
    // and later
    removeAllListeners(div, 'click')

DEMO

Hinweis: Wenn Ihr Code längere Zeit ausgeführt wird und Sie viele Elemente erstellen und entfernen, müssen Sie sicherstellen, dass die darin enthaltenen Elemente entfernt werden, _eventHandlerswenn Sie sie zerstören.

Felix Kling
quelle
@Florian: Natürlich kann der Code verbessert werden, aber es sollte Ihnen eine Idee geben ... viel Spaß beim Codieren!
Felix Kling
2
Haben Sie dies mit mehr als einem div-Element versucht? Die Knotenvariable wird tatsächlich in eine Zeichenfolge konvertiert, z. B. '[Objekt HTMLDivElement]'. Dies bedeutet, dass Sie am Ende alles zum selben Knoten hinzufügen.
Cstruter
@cstruter: Richtig ... das war in meinen frühen Tagen mit JavaScript ... Ich werde den Code korrigieren, wenn ich mehr Zeit finde. Danke für die Information.
Felix Kling
Ich denke, es gibt einen Tippfehler, addListener sollte addEvent
AGamePlayer
Beachten Sie, dass element.parentNodedies null sein kann. Sollte wahrscheinlich einen if-Check um diesen Code oben setzen.
Thecoolmacdude
37

Dadurch werden alle Listener von untergeordneten Elementen entfernt, bei großen Seiten ist dies jedoch langsam. Brutal einfach zu schreiben.

element.outerHTML = element.outerHTML;
Pabomben
quelle
2
Gute Antwort. Für Blattknoten scheint dies die beste Idee zu sein.
user3055938
3
document.querySelector('body').outerHTML = document.querySelector('body').outerHTMLarbeitete für mich.
Ryan
2
@ Ryan statt document.querySelector('body').outerHTMLdu kannst einfach tippendocument.body.outerHTML
Jay Dadhania
27

Verwenden Sie die eigene Funktion des Ereignis-Listeners remove(). Beispielsweise:

getEventListeners().click.forEach((e)=>{e.remove()})
JuanGG
quelle
2
Ich bin mir nicht sicher, warum dies nicht die richtige Antwort ist. Die Frage taucht so oft in SO auf und kann das Problem mithilfe der Klonmethode lösen.
Jimasun
42
Es scheint, dass dies getEventListenersnur in den WebKit-Entwicklungstools und in FireBug verfügbar ist. Nicht etwas, das Sie einfach in Ihrem Code aufrufen können.
corwin.amber
1
Wenn Sie Probleme haben, dies zum Laufen zu bringen, übergeben Sie ein Objekt als Argument an getEventListeners(). Beispiel: getEventListeners(document)odergetEventListeners(document.querySelector('.someclass'))
Luke
10
Dies scheint nur auf der Chrome- Konsole zu funktionieren . Selbst auf Ihrem Skript auf Seite funktioniert es nicht.
Reuel Ribeiro
4
getEventListeners(document).click.forEach((e)=>{e.remove()})erzeugt diesen Fehler:VM214:1 Uncaught TypeError: e.remove is not a function
Ryan
10

Wie corwin.amber sagt, gibt es Unterschiede zwischen Webkit und anderen.

In Chrome:

getEventListeners(document);

Damit erhalten Sie ein Objekt mit allen vorhandenen Ereignis-Listenern:

Object 
 click: Array[1]
 closePopups: Array[1]
 keyup: Array[1]
 mouseout: Array[1]
 mouseover: Array[1]
 ...

Von hier aus können Sie den Listener erreichen, den Sie entfernen möchten:

getEventListeners(document).copy[0].remove();

Also alle Event-Listener:

for(var eventType in getEventListeners(document)) {
   getEventListeners(document)[eventType].forEach(
      function(o) { o.remove(); }
   ) 
}

In Firefox

Ist ein bisschen anders, weil es einen Listener-Wrapper verwendet, der keine Entfernungsfunktion enthält. Sie müssen den Listener erhalten, den Sie entfernen möchten:

document.removeEventListener("copy", getEventListeners(document).copy[0].listener)

Alle Event-Listener:

for(var eventType in getEventListeners(document)) {
  getEventListeners(document)[eventType].forEach(
    function(o) { document.removeEventListener(eventType, o.listener) }
  ) 
}

Ich bin über diesen Beitrag gestolpert und habe versucht, den lästigen Kopierschutz einer Nachrichten-Website zu deaktivieren.

Genießen!

Jmakuc
quelle
Dies ist die beste Antwort, um gezielt Listener zu entfernen, z. B. wenn ein bestimmter Listener auf dem Dokumentknoten entfernt wird, ohne alle Listener zu entfernen.
Trevor
Dies funktioniert gut und beste Antwort. @ Jmakuc Vielen Dank.
Thavamani Kasi
5
Firefox sagt mir, dass getEventListenersdas nicht definiert ist?
Rovyko
Dies ist eine schlechte Lösung, da getEventListeners derzeit nur von Chrome unterstützt wird.
Michael Paccione
0

Um die Antworten zu vervollständigen, finden Sie hier Beispiele aus der Praxis zum Entfernen von Ereignissen, wenn Sie Websites besuchen und keine Kontrolle über den generierten HTML- und JavaScript-Code haben.

Einige nervige Websites verhindern, dass Sie Benutzernamen in Anmeldeformulare kopieren und einfügen können. Dies kann leicht umgangen werden, wenn das onpasteEreignis mit dem onpaste="return false"HTML-Attribut hinzugefügt wird. In diesem Fall müssen wir nur mit der rechten Maustaste auf das Eingabefeld klicken, in einem Browser wie Firefox "Element überprüfen" auswählen und das HTML-Attribut entfernen.

Wenn das Ereignis jedoch wie folgt über JavaScript hinzugefügt wurde:

document.getElementById("lyca_login_mobile_no").onpaste = function(){return false};

Wir müssen das Ereignis auch über JavaScript entfernen:

document.getElementById("lyca_login_mobile_no").onpaste = null;

In meinem Beispiel habe ich die ID "lyca_login_mobile_no" verwendet, da dies die Texteingabe-ID war, die von der Website verwendet wurde, die ich besuchte.

Eine andere Möglichkeit, das Ereignis zu entfernen (wodurch auch alle Ereignisse entfernt werden), besteht darin, den Knoten zu entfernen und einen neuen zu erstellen, wie wir es tun müssen, wenn addEventListenerEreignisse mit einer anonymen Funktion hinzugefügt werden, mit der wir nicht entfernen könnenremoveEventListener . Dies kann auch über die Browserkonsole erfolgen, indem ein Element überprüft, der HTML-Code kopiert, der HTML-Code entfernt und der HTML-Code an derselben Stelle eingefügt wird.

Es kann auch schneller und automatisierter über JavaScript erfolgen:

var oldNode = document.getElementById("lyca_login_mobile_no");
var newNode = oldNode.cloneNode(true);
oldNode.parentNode.insertBefore(newNode, oldNode);
oldNode.parentNode.removeChild(oldNode);

Update: Wenn die Web-App mit einem JavaScript-Framework wie Angular erstellt wurde, funktionieren die vorherigen Lösungen anscheinend nicht oder beschädigen die App nicht. Eine andere Problemumgehung, um das Einfügen zu ermöglichen, besteht darin, den Wert über JavaScript festzulegen:

document.getElementById("lyca_login_mobile_no").value = "username";

Im Moment weiß ich nicht, ob es eine Möglichkeit gibt, alle Ereignisse zur Formularüberprüfung und -beschränkung zu entfernen, ohne eine App zu beschädigen, die vollständig in JavaScript wie Angular geschrieben ist.

Taufe
quelle
0

eckig hat eine Polyfüllung für dieses Problem, können Sie überprüfen. Ich habe nicht viel verstanden, aber vielleicht kann es helfen.

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$1[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;
        }
    };

....

feyzullahyildiz
quelle
-1
var div = getElementsByTagName('div')[0]; /* first div found; you can use getElementById for more specific element */
div.onclick = null; // OR:
div.onclick = function(){};

//bearbeiten

Ich wusste nicht, mit welcher Methode Sie Ereignisse anhängen. Denn addEventListenerSie können dies verwenden:

div.removeEventListener('click',functionName,false); // functionName is the name of your callback function

Weitere Details

Ionuț Staicu
quelle
1
Wenn ich es so setze, div.onClick = somethingdann setzt es ein anderes Ereignis auf Click, aber das vorherige bleibt, also habe ich das vorherige und eines zum Beispiel null ...
Florian Müller
1
Funktioniert nicht, wenn Handler über hinzugefügt werden addEventListener().
Felix Kling
@Florian: Nein das ist nicht wahr. Wenn Sie diese Methode zum Hinzufügen eines Ereignishandlers verwenden, können Sie nur einen Handler für ein Ereignis haben. Aber es macht einen Unterschied, wenn Sie addEventListener()...
Felix Kling
aber ich habe es so gesehen, also wenn ich die vorherige Funktion noch einmal hinzugefügt habe, wird sie zweimal aufgerufen ... und wie Felix King sagt, funktioniert dies nicht mit addEventListener ...
Florian Müller
-1

Möglicherweise erledigt der Browser dies für Sie, wenn Sie Folgendes tun:

Kopieren Sie das divund seine Attribute und fügen Sie es vor dem alten ein. Verschieben Sie dann den Inhalt vom alten zum neuen und löschen Sie den alten?

Mic
quelle
Nun, das ist eigentlich eine gute Idee, aber völlig unperformant, wenn Sie dies für eine Vielzahl von Divs zwischen 1'000 und 1'000'000 tun müssen ... Ja, es ist ein großes Projekt;)
Florian Müller
6
1M Divs auf einer Seite? Sie werden vor diesem in andere Probleme geraten;) Kann dann Ereignisdelegation verwenden ...
Mic
-1

Entfernen aller Ereignisse am document :

Einzeiler:

for (key in getEventListeners(document)) { getEventListeners(document)[key].forEach(function(c) { c.remove() }) }

Hübsche Version:

for (key in getEventListeners(document)) {
  getEventListeners(document)[key].forEach(function(c) {
    c.remove()
  })   
}
Dorian
quelle
-1

Nur Chrome

Da ich versuche, einen EventListener innerhalb eines Winkelmessertests zu entfernen und im Test keinen Zugriff auf den Listener habe, werden im Folgenden alle Ereignis-Listener eines einzelnen Typs entfernt:

function(eventType){
    getEventListeners(window).[eventType].forEach(
        function(e){
            window.removeEventListener(eventType, e.listener)
        }
    );
}

Ich hoffe, dies hilft jemandem, da die vorherige Antwort die "Entfernen" -Methode verwendet hat, die seitdem nicht mehr funktioniert.

Filipe Melo
quelle
-1

Sie können einen weiteren Ereignis-Listener hinzufügen und aufrufen preventDefault(), um die Weitergabe der vorherigen Listener zu stoppen.

document.querySelectorAll('a.my-link').forEach((el) => {
  el.addEventListener('click', (ev) => {
    ev.preventDefault()
  })
})
Rafal Enden
quelle
-1

Eine Methode besteht darin, einen neuen Ereignis-Listener hinzuzufügen, der e.stopImmediatePropagation () aufruft.

Lacho Tomov
quelle