Wie kann ich überprüfen, ob ein dynamisch angehängter Ereignis-Listener vorhanden ist oder nicht?

100

Hier ist mein Problem: Ist es irgendwie möglich, die Existenz eines dynamisch angehängten Ereignis-Listeners zu überprüfen? Oder wie kann ich den Status der Eigenschaft "onclick" (?) In DOM überprüfen? Ich habe wie Stack Overflow im Internet nach einer Lösung gesucht, aber kein Glück. Hier ist mein HTML:

<a id="link1" onclick="linkclick(event)"> link 1 </a>
<a id="link2"> link 2 </a> <!-- without inline onclick handler -->

Dann hänge ich in Javascript dynamisch erstellten Ereignis-Listener an den 2. Link an:

document.getElementById('link2').addEventListener('click', linkclick, false);

Der Code läuft gut, aber alle meine Versuche, diesen angehängten Listener zu erkennen, schlagen fehl:

// test for #link2 - dynamically created eventlistener
alert(elem.onclick); // null
alert(elem.hasAttribute('onclick')); // false
alert(elem.click); // function click(){[native code]} // btw, what's this?

jsFiddle ist da . Wenn Sie auf "Add onclick for 2" und dann auf "[link 2]" klicken, wird das Ereignis gut ausgelöst, aber der "Test link 2" meldet immer false. Kann jemand helfen?

Stano
quelle
1
Es tut mir leid zu sagen, aber es ist unmöglich, die Ereignisbindungen mit Ihrer aktuellen Methode zu erhalten: stackoverflow.com/questions/5296858/…
Ivan
1
Sie können es mit Chrome Dev Tool tun: Stackoverflow.com/a/41137585/863115
Arufian
Sie können dies tun, indem Sie einen eigenen Speicher erstellen, der die Listener verfolgt. Siehe meine Antwort für mehr.
Angel Politis
Wenn das Ziel darin besteht, zu verhindern, dass ein bereits hinzugefügtes Ereignis erneut hinzugefügt wird , ist hier die richtige Antwort . Wenn Sie eine benannte Funktion anstelle einer anonymen verwenden, werden doppelte identische Ereignis-Listener verworfen, und Sie müssen sich keine Gedanken darüber machen.
Syknapse
Wenn Sie Bedenken haben, doppelte Listener zu haben, entfernen Sie den aktuellen Ereignis-Listener, bevor Sie ihn erneut hinzufügen. Es ist nicht perfekt, aber es ist einfach.
Jacksonkr

Antworten:

48

Es gibt keine Möglichkeit zu überprüfen, ob dynamisch angehängte Ereignis-Listener vorhanden sind oder nicht.

Sie können nur sehen, ob ein Ereignis-Listener angehängt ist, indem Sie Ereignis-Listener wie folgt anhängen:

elem.onclick = function () { console.log (1) }

Sie können dann testen, ob ein Ereignis-Listener angehängt wurde, onclickindem Sie zurückkehren !!elem.onclick(oder etwas Ähnliches).

Ivan
quelle
32

Ich habe so etwas gemacht:

const element = document.getElementById('div');

if (element.getAttribute('listener') !== 'true') {
     element.addEventListener('click', function (e) {
         const elementClicked = e.target;
         elementClicked.setAttribute('listener', 'true');
         console.log('event has been attached');
    });
}

Erstellen eines speziellen Attributs für ein Element, wenn der Listener angehängt ist, und Überprüfen, ob es vorhanden ist.

Karol Grabowski
quelle
4
Dies ist der Ansatz, den ich in der Vergangenheit verwendet habe. Meine Empfehlung wäre, eine sehr spezifische Syntaxstruktur zu verwenden. IE anstelle von "Listener" verwenden Sie das Ereignis selbst. Also "Datenereignis-Klick". Dies bietet eine gewisse Flexibilität für den Fall, dass Sie mehr als ein Ereignis durchführen möchten, und hält die Dinge ein bisschen besser lesbar.
conrad10781
Dies mit dem Zusatz von @ conrad10781 scheint der zuverlässigste und einfachste Weg zu sein. Wenn das Element aus irgendeinem Grund erneut gerendert wird und der Ereignis-Listener getrennt wird, wird dieses Attribut ebenfalls zurückgesetzt.
Arye Eidelman
23

Ich würde einen Booleschen Wert außerhalb Ihrer Funktion erstellen, der als FALSE beginnt und beim Anhängen des Ereignisses auf TRUE gesetzt wird. Dies würde als eine Art Flagge für Sie dienen, bevor Sie das Ereignis erneut anhängen. Hier ist ein Beispiel für die Idee.

// initial load
var attached = false;

// this will only execute code once
doSomething = function()
{
 if (!attached)
 {
  attached = true;
  //code
 }
} 

//attach your function with change event
window.onload = function()
{
 var txtbox = document.getElementById('textboxID');

 if (window.addEventListener)
 {
  txtbox.addEventListener('change', doSomething, false);
 }
 else if(window.attachEvent)
 {
  txtbox.attachEvent('onchange', doSomething);
 }
}
Cesar
quelle
Dazu müssen Sie den Code des angehängten Ereignisses ändern, um zu verfolgen, ob es angehängt ist (ähnlich dieser oder dieser Antwort ). Es wird nicht funktionieren, wenn Sie den Code nicht kontrollieren.
user202729
6

tl; dr : Nein, Sie können dies nicht auf nativ unterstützte Weise tun.


Die einzige Möglichkeit, dies zu erreichen, besteht darin, ein benutzerdefiniertes Speicherobjekt zu erstellen, in dem Sie die hinzugefügten Listener aufzeichnen. Etwas in der folgenden Richtung:

/* Create a storage object. */
var CustomEventStorage = [];

Schritt 1: Zunächst benötigen Sie eine Funktion, die das Speicherobjekt durchlaufen und den Datensatz eines Elements mit dem angegebenen Element (oder false) zurückgeben kann.

/* The function that finds a record in the storage by a given element. */
function findRecordByElement (element) {
    /* Iterate over every entry in the storage object. */
    for (var index = 0, length = CustomEventStorage.length; index < length; index++) {
        /* Cache the record. */
        var record = CustomEventStorage[index];

        /* Check whether the given element exists. */
        if (element == record.element) {
            /* Return the record. */
            return record;
        }
    }

    /* Return false by default. */
    return false;
}

Schritt 2: Dann benötigen Sie eine Funktion, die einen Ereignis-Listener hinzufügen, aber auch den Listener in das Speicherobjekt einfügen kann.

/* The function that adds an event listener, while storing it in the storage object. */
function insertListener (element, event, listener, options) {
    /* Use the element given to retrieve the record. */
    var record = findRecordByElement(element);

    /* Check whether any record was found. */
    if (record) {
        /* Normalise the event of the listeners object, in case it doesn't exist. */
        record.listeners[event] = record.listeners[event] || [];
    }
    else {
        /* Create an object to insert into the storage object. */
        record = {
            element: element,
            listeners: {}
        };

        /* Create an array for event in the record. */
        record.listeners[event] = [];

        /* Insert the record in the storage. */
        CustomEventStorage.push(record);
    }

    /* Insert the listener to the event array. */
    record.listeners[event].push(listener);

    /* Add the event listener to the element. */
    element.addEventListener(event, listener, options);
}

Schritt 3: In Bezug auf die tatsächliche Anforderung Ihrer Frage benötigen Sie die folgende Funktion, um zu überprüfen, ob einem Element ein Ereignis-Listener für ein bestimmtes Ereignis hinzugefügt wurde.

/* The function that checks whether an event listener is set for a given event. */
function listenerExists (element, event, listener) {
    /* Use the element given to retrieve the record. */
    var record = findRecordByElement(element);

    /* Check whether a record was found & if an event array exists for the given event. */
    if (record && event in record.listeners) {
        /* Return whether the given listener exists. */
        return !!~record.listeners[event].indexOf(listener);
    }

    /* Return false by default. */
    return false;
}

Schritt 4: Schließlich benötigen Sie eine Funktion, mit der Sie einen Listener aus dem Speicherobjekt löschen können.

/* The function that removes a listener from a given element & its storage record. */
function removeListener (element, event, listener, options) {
    /* Use the element given to retrieve the record. */
    var record = findRecordByElement(element);

    /* Check whether any record was found and, if found, whether the event exists. */
    if (record && event in record.listeners) {
        /* Cache the index of the listener inside the event array. */
        var index = record.listeners[event].indexOf(listener);

        /* Check whether listener is not -1. */
        if (~index) {
            /* Delete the listener from the event array. */
            record.listeners[event].splice(index, 1);
        }

        /* Check whether the event array is empty or not. */
        if (!record.listeners[event].length) {
            /* Delete the event array. */
            delete record.listeners[event];
        }
    }

    /* Add the event listener to the element. */
    element.removeEventListener(event, listener, options);
}

Snippet:


Obwohl mehr als fünf Jahre vergangen sind, seit das OP die Frage gestellt hat, glaube ich, dass Menschen, die in Zukunft darauf stoßen, von dieser Antwort profitieren werden. Sie können also gerne Vorschläge oder Verbesserungen dazu machen. 😊

Engel Politis
quelle
Vielen Dank für diese Lösung, sie ist unkompliziert und robust. Eine Bemerkung, es gibt einen kleinen Fehler. Die Funktion "removeListener" prüft, ob das Ereignisarray leer ist oder nicht, aber das ternäre ist falsch. Es sollte "if (record.listeners [event] .length! = - 1)" lauten.
JPA
5

Sie können jederzeit manuell überprüfen, ob Ihr EventListener vorhanden ist, indem Sie beispielsweise den Chrome-Inspektor verwenden. Auf der Registerkarte "Element" befindet sich die traditionelle Unterregisterkarte "Stile" und in der Nähe eine weitere: "Ereignis-Listener". Dadurch erhalten Sie eine Liste aller EventListener mit ihren verknüpften Elementen.

Paul Leclerc
quelle
5

Es scheint seltsam, dass diese Methode nicht existiert. Ist es Zeit, es endlich hinzuzufügen?

Wenn Sie wollten, könnten Sie so etwas wie das Folgende:

var _addEventListener = EventTarget.prototype.addEventListener;
var _removeEventListener = EventTarget.prototype.removeEventListener;
EventTarget.prototype.events = {};
EventTarget.prototype.addEventListener = function(name, listener, etc) {
  var events = EventTarget.prototype.events;
  if (events[name] == null) {
    events[name] = [];
  }

  if (events[name].indexOf(listener) == -1) {
    events[name].push(listener);
  }

  _addEventListener(name, listener);
};
EventTarget.prototype.removeEventListener = function(name, listener) {
  var events = EventTarget.prototype.events;

  if (events[name] != null && events[name].indexOf(listener) != -1) {
    events[name].splice(events[name].indexOf(listener), 1);
  }

  _removeEventListener(name, listener);
};
EventTarget.prototype.hasEventListener = function(name) {
  var events = EventTarget.prototype.events;
  if (events[name] == null) {
    return false;
  }

  return events[name].length;
};
1,21 Gigawatt
quelle
3

Hier ist ein Skript, mit dem ich überprüft habe, ob ein dynamisch angehängter Ereignis-Listener vorhanden ist. Ich habe jQuery verwendet, um einen Ereignishandler an ein Element anzuhängen und dann dieses Ereignis auszulösen (in diesem Fall das Ereignis 'click'). Auf diese Weise kann ich Ereigniseigenschaften abrufen und erfassen, die nur vorhanden sind, wenn der Ereignishandler angehängt ist.

var eventHandlerType;

$('#contentDiv').on('click', clickEventHandler).triggerHandler('click');

function clickEventHandler(e) {
    eventHandlerType = e.type;
}

if (eventHandlerType === 'click') {
    console.log('EventHandler "click" has been applied');
}
dsmith63
quelle
2
Sie können dem Element, das Ihr Element enthält, auch eine Eigenschaft zuweisen, indem Sie es als Element markieren, an das ein Ereignis angehängt ist.
Justin
2

Es scheint keine browserübergreifende Funktion zu geben, die nach Ereignissen sucht, die unter einem bestimmten Element registriert sind.

Es ist jedoch möglich, die Rückruffunktionen für Elemente in einigen Browsern mithilfe ihrer Entwicklungstools anzuzeigen. Dies kann hilfreich sein, wenn Sie versuchen, die Funktionsweise einer Webseite zu bestimmen oder Code zu debuggen.

Feuerfuchs

Zeigen Sie zunächst das Element auf der Registerkarte Inspektor in den Entwicklertools an. Das kann gemacht werden:

  • Klicken Sie auf der Seite mit der rechten Maustaste auf das Element auf der Webseite, das Sie überprüfen möchten, und wählen Sie im Menü "Element überprüfen" aus.
  • Verwenden Sie in der Konsole eine Funktion, um das Element auszuwählen, z. B. document.querySelector , und klicken Sie dann auf das Symbol neben dem Element, um es auf der Registerkarte Inspektor anzuzeigen.

Wenn Ereignisse für das Element registriert wurden, wird neben dem Element eine Schaltfläche mit dem Wort Ereignis angezeigt. Wenn Sie darauf klicken, werden die Ereignisse angezeigt, die für das Element registriert wurden. Durch Klicken auf den Pfeil neben einem Ereignis können Sie die Rückruffunktion für dieses Ereignis anzeigen.

Chrom

Zeigen Sie zunächst das Element auf der Registerkarte Elemente in den Entwicklertools an. Das kann gemacht werden:

  • Klicken Sie auf der Seite mit der rechten Maustaste auf das Element auf der Webseite, das Sie überprüfen möchten, und wählen Sie im Menü die Option "Überprüfen" aus
  • Verwenden Sie in der Konsole eine Funktion, um das Element auszuwählen, z. B. document.querySelector , klicken Sie mit der rechten Maustaste auf das Element und wählen Sie "In Elementen anzeigen", um es auf der Registerkarte " Inspektor " anzuzeigen .

In der Nähe des Abschnitts des Fensters, in dem der Baum mit den Webseitenelementen angezeigt wird, sollte sich ein weiterer Abschnitt mit einer Registerkarte mit dem Titel "Ereignis-Listener" befinden. Wählen Sie diese Option aus, um Ereignisse anzuzeigen, die für das Element registriert wurden. Um den Code für ein bestimmtes Ereignis anzuzeigen, klicken Sie auf den Link rechts davon.

In Chrome können Ereignisse für ein Element auch mit der Funktion getEventListeners gefunden werden. Basierend auf meinen Tests listet die Funktion getEventListeners jedoch keine Ereignisse auf, wenn mehrere Elemente an sie übergeben werden. Wenn Sie alle Elemente auf der Seite mit Listenern suchen und die Rückruffunktionen für diese Listener anzeigen möchten, können Sie dazu den folgenden Code in der Konsole verwenden:

var elems = document.querySelectorAll('*');

for (var i=0; i <= elems.length; i++) {
    var listeners = getEventListeners(elems[i]);

    if (Object.keys(listeners).length < 1) {
        continue;
    }

    console.log(elems[i]);

    for (var j in listeners) {
        console.log('Event: '+j);

        for (var k=0; k < listeners[j].length; k++) {
            console.log(listeners[j][k].listener);
        }
    }
}

Bitte bearbeiten Sie diese Antwort, wenn Sie wissen, wie Sie dies in den angegebenen Browsern oder in anderen Browsern tun können.

Dave F.
quelle
1

Ich habe das gerade herausgefunden, indem ich versucht habe zu sehen, ob meine Veranstaltung beigefügt ist ...

wenn Sie tun :

item.onclick

es wird "null" zurückgeben

aber wenn Sie dies tun:

item.hasOwnProperty('onclick')

dann ist es "WAHR"

Wenn Sie also "addEventListener" zum Hinzufügen von Ereignishandlern verwenden, können Sie nur über "hasOwnProperty" darauf zugreifen. Ich wünschte, ich wüsste warum oder wie, aber leider habe ich nach Recherchen keine Erklärung gefunden.

Carinlynchin
quelle
2
onclickist getrennt von .addEventListener- es beeinflusst ein Attribut, während .addEventListenerdies nicht der Fall ist
Zach Saucier
1

Wenn ich es gut verstehe, können Sie nur überprüfen, ob ein Listener überprüft wurde, nicht jedoch, welcher Listener speziell der Moderator ist.

Ein Ad-hoc-Code würde also die Lücke füllen, um Ihren Codierungsfluss zu handhaben. Eine praktische Methode wäre das Erstellen einer stateusing-Variablen. Fügen Sie beispielsweise den Checker eines Listeners wie folgt hinzu:

var listenerPresent=false

Wenn Sie dann einen Listener einstellen, ändern Sie einfach den Wert:

listenerPresent=true

Anschließend können Sie im Rückruf Ihres eventListener bestimmte Funktionen zuweisen und auf dieselbe Weise den Zugriff auf Funktionen abhängig von einem bestimmten Status als Variable verteilen, z. B.:

accessFirstFunctionality=false
accessSecondFunctionality=true
accessThirdFunctionality=true
Webfrau
quelle
1

Entfernen Sie einfach das Ereignis, bevor Sie es hinzufügen:

document.getElementById('link2').removeEventListener('click', linkclick, false);
document.getElementById('link2').addEventListener('click', linkclick, false);
Entretoisieren
quelle
Das ist ein guter Trick, aber ich gehe davon aus, dass er nur funktioniert, wenn Sie einen Verweis auf die Funktion haben, die einer der derzeit "hinzugefügten" Ereignis-Listener ist. Ich denke, dies ist eindeutig ein Mangel der Standard-API. Wenn wir einen Ereignis-Listener hinzufügen können, sollte es auch möglich sein, zu überprüfen, welche Ereignis-Listener bisher hinzugefügt wurden. Es ist fast so, als ob Event-Listener derzeit "nur Variablen schreiben", was wie ein obskures Konzept erscheint.
Panu Logic
0

Ich habe gerade ein Skript geschrieben, mit dem Sie dies erreichen können. Es gibt Ihnen zwei globale Funktionen: hasEvent(Node elm, String event)und getEvents(Node elm)die Sie nutzen können. Beachten Sie, dass die EventTargetPrototypmethode geändert add/RemoveEventListenerwird und nicht für Ereignisse funktioniert, die über HTML-Markup oder Javascript-Syntax von hinzugefügt wurdenelm.on_event = ...

Mehr Infos bei GitHub

Live-Demo

Skript:

var hasEvent,getEvents;!function(){function b(a,b,c){c?a.dataset.events+=","+b:a.dataset.events=a.dataset.events.replace(new RegExp(b),"")}function c(a,c){var d=EventTarget.prototype[a+"EventListener"];return function(a,e,f,g,h){this.dataset.events||(this.dataset.events="");var i=hasEvent(this,a);return c&&i||!c&&!i?(h&&h(),!1):(d.call(this,a,e,f),b(this,a,c),g&&g(),!0)}}hasEvent=function(a,b){var c=a.dataset.events;return c?new RegExp(b).test(c):!1},getEvents=function(a){return a.dataset.events.replace(/(^,+)|(,+$)/g,"").split(",").filter(function(a){return""!==a})},EventTarget.prototype.addEventListener=c("add",!0),EventTarget.prototype.removeEventListener=c("remove",!1)}();
Gaurang Tandon
quelle
-1

Theoretisch können Sie addEventListener und removeEventListener huckepack nehmen, um dem 'this'-Objekt ein Flag zum Entfernen hinzuzufügen. Hässlich und ich habe nicht getestet ...

Kofifus
quelle