jQuery trova gestori di eventi registrati con un oggetto


555

Devo trovare quali gestori di eventi sono registrati su un oggetto.

Per esempio:

$("#el").click(function() {...});
$("#el").mouseover(function() {...});

$("#el")ha registrato click e mouseover .

Esiste una funzione per scoprirlo, ed eventualmente iterare sui gestori di eventi?

Se non è possibile su un oggetto jQuery con metodi adeguati, è possibile su un semplice oggetto DOM?



2
supporta sia jQuery pre che post 1.8:var events = (jQuery._data || jQuery.data)(elem, 'events');
oriadam il

2
Si noti che è possibile utilizzare gli strumenti di sviluppo FF e Chrome (F12) per visualizzare questi listener di eventi. Vedi developers.google.com/web/tools/chrome-devtools/debug/… e developer.mozilla.org/en-US/docs/Tools/Page_Inspector/How_to/…
oriadam,

Risposte:


691

A partire da jQuery 1.8, i dati dell'evento non sono più disponibili dalla "API pubblica" per i dati. Leggi questo post sul blog jQuery . Ora dovresti usare questo invece:

jQuery._data( elem, "events" );

elem dovrebbe essere un elemento HTML, non un oggetto jQuery o un selettore.

Si noti che questa è una struttura interna "privata" e non deve essere modificata. Utilizzare questo solo a scopo di debug.

Nelle versioni precedenti di jQuery, potrebbe essere necessario utilizzare il vecchio metodo che è:

jQuery( elem ).data( "events" );

222
ma puoi ancora usare $._data($(elem).get(0), "events")
bullgare il

10
blog.jquery.com/2011/11/08/building-a-slimmer-jquery .data ("eventi"): jQuery archivia i dati relativi agli eventi in un oggetto dati denominato (wait) eventi su ciascun elemento. Questa è una struttura di dati interna, quindi in 1.8 verrà rimossa dallo spazio dei nomi dei dati dell'utente in modo che non sia in conflitto con elementi con lo stesso nome. È ancora possibile accedere ai dati degli eventi di jQuery tramite jQuery._data (elemento, "eventi"), ma tenere presente che si tratta di una struttura di dati interna non documentata e che non deve essere modificata.
Sam Greenhalgh,

Ho usato questo metodo per provare a scoprire l'evento click di un pulsante. Nella console di Chrome è stato mostrato handler: function () {all'interno della proprietà click. Ho dovuto fare doppio clic sulla parte della funzione per espanderla e mostrare l'intero contenuto della funzione.
Jim,

@jim yeaaah, il doppio clic è la risposta
Adib Aroui,

2
Supporta perfettamente entrambe le opzioni:var events = (jQuery._data || jQuery.data)(elem, 'events');
Oriadam,

84

Puoi farlo eseguendo la scansione degli eventi (a partire da jQuery 1.8+), in questo modo:

$.each($._data($("#id")[0], "events"), function(i, event) {
  // i is the event type, like "click"
  $.each(event, function(j, h) {
    // h.handler is the function being called
  });
});

Ecco un esempio con cui puoi giocare:

$(function() {
  $("#el").click(function(){ alert("click"); });
  $("#el").mouseover(function(){ alert("mouseover"); });

  $.each($._data($("#el")[0], "events"), function(i, event) {
    output(i);
    $.each(event, function(j, h) {
        output("- " + h.handler);
    });
  });
});

function output(text) {
    $("#output").html(function(i, h) {
        return h + text + "<br />";
    });
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div id="el">Test</div>
<code>
    <span id="output"></span>
</code>


2
Questa è la risposta corretta Il punto cruciale è la seconda metà. Questo mi ha aiutato a trovare un problema in meno di un minuto che avrebbe impiegato più di un'ora se avessi cercato in tutto il codice. Grazie!
Andrew Ensley,

2
Funziona con 1.4, ma non in jQuery 1.8.2.
Timo Kähkönen,

15
Per jQuery 1.8+, è necessario utilizzare il metodo di 'dati privati': jQuery._data( jQuery("#el")[0], "events" );invece del metodo 'dati pubblici': jQuery("#el").data("events"). L' eventsoggetto non è stato effettivamente archiviato .data()per molto tempo, abbiamo eliminato alcuni byte di codice rimuovendo questo "proxy" dalla "API pubblica"
gnarf

36

Per jQuery 1.8+, questo non funzionerà più perché i dati interni sono collocati in un oggetto diverso.

L'ultimo modo non ufficiale (ma funziona anche nelle versioni precedenti, almeno in 1.7.2) ora è - $._data(element, "events")

Il trattino basso ("_") è ciò che fa la differenza qui. Internamente, sta chiamando $.data(element, name, null, true), l'ultimo (quarto) parametro è uno interno ("pvt").


$ ._ data ("body", "events") non definito $ (). jquery; "1.7.1" (provato 1.7.2 e 1.8.1 per tutto il tempo "indefinito")
Mars Robertson,

2
@Michal - api.jquery.com/jQuery.data afferma che accetta un elemento, non un selettore.
PhistucK,

1
Ora funziona benissimo: $ ._ data ($ ("body"). Get (0), "events") O ancora meglio: $ ("body"). Data ("events")!
Mars Robertson,

2
FWIW - Sottolineare che chiama "internamente" l'altra funzione di dati con un parametro che specificamente non documentiamo probabilmente non è necessario. Ma sì, jQuery._data( element, "events" )è il modo "corretto" per ottenere queste informazioni ora.
Gnarf,

34

Spina senza vergogna, ma puoi usare findHandlerJS

Per usarlo devi solo trovare findHandlersJS (o semplicemente copiare e incollare il codice javascript non elaborato nella finestra della console di Chrome) e specificare il tipo di evento e un selettore jquery per gli elementi che ti interessano.

Per il tuo esempio potresti trovare rapidamente i gestori di eventi che hai citato facendo

findEventHandlers("click", "#el")
findEventHandlers("mouseover", "#el")

Questo è ciò che viene restituito:

  • element
    L' elemento effettivo in cui è stato registrato il gestore eventi
  • eventi
    Matrice con informazioni sui gestori di eventi jquery per il tipo di evento a cui siamo interessati (ad es. clic, modifica, ecc.)
    • gestore
      Metodo del gestore di eventi effettivi che è possibile visualizzare facendo clic con il pulsante destro del mouse e selezionando Mostra definizione funzione
    • selettore
      Il selettore fornito per eventi delegati. Sarà vuoto per eventi diretti.
    • target
      Elenco con gli elementi targetizzati da questo gestore eventi. Ad esempio, per un gestore eventi delegato che è registrato nell'oggetto documento e ha come target tutti i pulsanti in una pagina, questa proprietà elencherà tutti i pulsanti nella pagina. Puoi passarli sopra e vederli evidenziati in cromo.

Puoi provarlo qui


Penso che dovrebbe essere la risposta accettata. Questo è l'unico che funziona anche per me. È molto accurato poiché passa attraverso tutti gli elementi alla ricerca di eventi.
Marquinho Peli,

12

A questo scopo utilizzo il plugin eventbug per firebug.


Grazie, ottimo consiglio. L'estensione aggiunge una scheda a Firebug ("Eventi") che mostra gli eventi della pagina, così puoi espanderli facilmente.
Gruber,

11
Inoltre, Chrome Developer Tools ha "Listener di eventi" nella scheda "Elementi" e "Punti di interruzione del listener di eventi" nella scheda "Fonti".
Clayzermk1,

10

Ho combinato entrambe le soluzioni da @jps a una funzione:

jQuery.fn.getEvents = function() {
    if (typeof(jQuery._data) === 'function') {
        return jQuery._data(this.get(0), 'events') || {};
    }

    // jQuery version < 1.7.?
    if (typeof(this.data) === 'function') {
        return this.data('events') || {};
    }

    return {};
};

Ma attenzione, questa funzione può restituire solo eventi impostati usando jQuery stesso.


5

A partire dalla versione 1.9 non esiste un modo documentato per recuperare gli eventi, se non quello di utilizzare il plugin Migrate per ripristinare il vecchio comportamento. È possibile utilizzare il metodo _.data () come menzioni jps, ma si tratta di un metodo interno. Quindi fai solo la cosa giusta e usa il plugin Migrate se hai bisogno di questa funzionalità.

Dalla documentazione di jQuery in poi .data("events")

Prima di 1.9, .data ("eventi") poteva essere utilizzato per recuperare la struttura di dati di eventi interni privi di documenti di jQuery per un elemento se nessun altro codice aveva definito un elemento di dati con il nome "eventi". Questo caso speciale è stato rimosso in 1.9. Non esiste un'interfaccia pubblica per recuperare questa struttura di dati interna e non è documentata. Tuttavia, il plugin jQuery Migrate ripristina questo comportamento per il codice che dipende da esso.


La risposta accettata mostra anche chiaramente il nuovo modo corretto per ottenerlo per le versioni recenti: jQuery._data( elem, "events" );...
Ian

2
Un modo privato e senza documenti non sarà mai un modo corretto . Il modo corretto, ovvero documentato, pubblico e previsto, è utilizzare il plug-in Migrate.
Oligofren,

3
Sembra che tu abbia frainteso il punto del plugin Migrate. jQuery ha rimosso le funzionalità obsolete e il plug-in Migrate aiuta a migrare il codice dello sviluppatore verso le versioni più recenti in modo che possano trarre immediatamente vantaggio da nuove funzionalità e miglioramenti, ma non perderne la funzionalità. Ha lo scopo di aiutare il programmatore a vedere cosa devono fare per iniziare a utilizzare correttamente le nuove versioni di jQuery. Non dovresti usarlo in produzione per ripristinare le funzionalità. Inoltre, molte cose non sono documentate e aggiornate nella documentazione di jQuery - l'hanno già sottolineato, quindi non è un motivo
Ian,

Inoltre, se è incluso come suggerimento nel blog jQuery, lo userei
Ian

Il tuo ragionamento sul plugin Migrate sembra ragionevole. OK se cancello la mia risposta?
oligofren,

5

Per verificare la presenza di eventi su un elemento:

var events = $._data(element, "events")

Nota che funzionerà solo con i gestori di eventi diretti, se stai usando $ (document) .on ("nome-evento", "selettore jq", funzione () {// logica}), vorrai vedere il getEvents funziona in fondo a questa risposta

Per esempio:

 var events = $._data(document.getElementById("myElemId"), "events")

o

 var events = $._data($("#myElemId")[0], "events")

Esempio completo:

<html>
    <head>
        <script src="//ajax.googleapis.com/ajax/libs/jquery/1.8.0/jquery.min.js" type="text/javascript"></script>
        <script>
            $(function() {
                $("#textDiv").click(function() {
                    //Event Handling
                });
                var events = $._data(document.getElementById('textDiv'), "events");
                var hasEvents = (events != null);
            });
        </script>
    </head>
    <body>
        <div id="textDiv">Text</div>
    </body>
</html>

Un modo più completo di controllo, che include listener dinamici, installato con $ (documento) .on

function getEvents(element) {
    var elemEvents = $._data(element, "events");
    var allDocEvnts = $._data(document, "events");
    for(var evntType in allDocEvnts) {
        if(allDocEvnts.hasOwnProperty(evntType)) {
            var evts = allDocEvnts[evntType];
            for(var i = 0; i < evts.length; i++) {
                if($(element).is(evts[i].selector)) {
                    if(elemEvents == null) {
                        elemEvents = {};
                    }
                    if(!elemEvents.hasOwnProperty(evntType)) {
                        elemEvents[evntType] = [];
                    }
                    elemEvents[evntType].push(evts[i]);
                }
            }
        }
    }
    return elemEvents;
}

Esempio di utilizzo:

getEvents($('#myElemId')[0])

Questo getEventsmetodo è eccessivamente eccezionale, ma il fatto è che fornisce voci duplicate in IE11 (lo so, di nuovo IE, ma le aziende ne hanno bisogno ...). EDIT: $ ._ data contiene eventi duplicati per element, anche se su FF non contiene alcun mondo ... Weird IE. Ma è importante fare attenzione a questa possibilità di avere eventi duplicati.
Dominik Szymański il

Oh, Tom, in realtà è il tuo codice che moltiplica gli eventi ad ogni esecuzione di questo metodo. Non bene.
Dominik Szymański il

4

Ho creato un selettore jQuery personalizzato che verifica sia la cache di jQuery dei gestori di eventi assegnati sia elementi che utilizzano il metodo nativo per aggiungerli:

(function($){

    $.find.selectors[":"].event = function(el, pos, match) {

        var search = (function(str){
            if (str.substring(0,2) === "on") {str = str.substring(2);}
            return str;
        })(String(match[3]).trim().toLowerCase());

        if (search) {
            var events = $._data(el, "events");
            return ((events && events.hasOwnProperty(search)) || el["on"+search]);
        }

        return false;

    };

})(jQuery);

Esempio:

$(":event(click)")

Ciò restituirà elementi a cui è collegato un gestore di clic.


2

In un browser moderno con ECMAScript 5.1 / Array.prototype.map, puoi anche usare

jQuery._data(DOCUMENTELEMENT,'events')["EVENT_NAME"].map(function(elem){return elem.handler;});

nella tua console del browser, che stamperà l'origine dei gestori, delimitata da virgole. Utile per dare un'occhiata a ciò che sta accadendo in un particolare evento.


jQuery._data('ct100_ContentPlaceHolder1_lcsSection','events')["EVENT_NAME"].map(function(elem){return elem.handler;}); Uncaught TypeError: impossibile leggere la proprietà 'EVENT_NAME' di undefined in <anonimo>: 1: 62
Mike W

'ct100_ContentPlaceHolder1_lcsSection'è una stringa, non un elemento DOM.
Jesan Fafon,

2

Gli eventi possono essere recuperati utilizzando:

jQuery(elem).data('events');

o jQuery 1.8+:

jQuery._data(elem, 'events');

Nota: gli eventi associati a $('selector').live('event', handler) possono essere recuperati utilizzando:

jQuery(document).data('events')

2
jQuery (document) .data ('events') mi dà undefined
Mike W

1

Devo dire che molte delle risposte sono interessanti, ma recentemente ho avuto un problema simile e la soluzione è stata estremamente semplice seguendo il DOM. È diverso perché non iterate ma mirate direttamente all'evento di cui avete bisogno, ma di seguito darò una risposta più generale.

Ho avuto un'immagine di fila:

<table>
  <td><tr><img class="folder" /></tr><tr>...</tr></td>
</table>

E a quell'immagine era associato un gestore eventi click:

imageNode.click(function () { ... });

La mia intenzione era di espandere l'area cliccabile su tutta la riga, quindi ho prima ottenuto tutte le immagini e le relative righe:

tableNode.find("img.folder").each(function () {
  var tr;

  tr = $(this).closest("tr");
  // <-- actual answer
});

Ora nella riga di risposta effettiva ho appena fatto la seguente, dando una risposta alla domanda originale:

tr.click(this.onclick);

Quindi ho recuperato il gestore eventi direttamente dall'elemento DOM e l'ho inserito nel gestore eventi click jQuery. Funziona come un fascino.

Ora, al caso generale. Ai vecchi tempi pre-jQuery si potevano ottenere tutti gli eventi collegati a un oggetto con due funzioni semplici ma potenti donate a noi mortali da Douglas Crockford :

function walkTheDOM(node, func)
{
  func(node);
  node = node.firstChild;
  while (node)
  {
    walkTheDOM(node, func);
    node = node.nextSibling;
  }
}

function purgeEventHandlers(node)
{
  walkTheDOM(node, function (n) {
    var f;

    for (f in n)
    {
      if (typeof n[f] === "function")
      {
        n[f] = null;
      }
    }
  });
}


0

Un altro modo per farlo è semplicemente usare jQuery per afferrare l'elemento, quindi passare attraverso Javascript reale per ottenere e impostare e giocare con i gestori di eventi. Per esempio:

var oldEventHandler = $('#element')[0].onclick;
// Remove event handler
$('#element')[0].onclick = null;
// Switch it back
$('#element')[0].onclick = oldEventHandler;

1
Penso che jQuery esegua l'ottimizzazione della gestione degli eventi che penso sia elusa dal tuo codice qui.
Emile Bergeron,

Grazie, sì, ho avuto la sensazione che fosse confuso - qualche buon link per saperne di più sull'ottimizzazione?
tempranova,

0

Ho combinato alcune delle risposte sopra e ho creato questo script dall'aspetto folle ma funzionale che elenca, si spera, la maggior parte degli ascoltatori di eventi sull'elemento dato. Sentiti libero di ottimizzarlo qui.

var element = $("#some-element");

// sample event handlers
element.on("mouseover", function () {
  alert("foo");
});

$(".parent-element").on("mousedown", "span", function () {
  alert("bar");
});

$(document).on("click", "span", function () {
  alert("xyz");
});

var collection = element.parents()
  .add(element)
  .add($(document));
collection.each(function() {
  var currentEl = $(this) ? $(this) : $(document);
  var tagName = $(this)[0].tagName ? $(this)[0].tagName : "DOCUMENT";
  var events = $._data($(this)[0], "events");
  var isItself = $(this)[0] === element[0]
  if (!events) return;
  $.each(events, function(i, event) {
    if (!event) return;
    $.each(event, function(j, h) {
      var found = false;        
      if (h.selector && h.selector.length > 0) {
        currentEl.find(h.selector).each(function () {
          if ($(this)[0] === element[0]) {
            found = true;
          }
        });
      } else if (!h.selector && isItself) {
        found = true;
      }

      if (found) {
        console.log("################ " + tagName);
        console.log("event: " + i);
        console.log("selector: '" + h.selector + "'");
        console.log(h.handler);
      }
    });
  });
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>

<div class="parent-element">
  <span id="some-element"></span>
</div>


0

jQuery non ti consente semplicemente di accedere agli eventi per un determinato elemento. Puoi accedervi usando un metodo interno non documentato

$._data(element, "events")

Ma non ti darà ancora tutti gli eventi, per essere precisi non ti mostrerà gli eventi assegnati

$([selector|element]).on()

Questi eventi sono memorizzati nel documento, quindi puoi recuperarli sfogliando

$._data(document, "events")

ma è un duro lavoro, poiché ci sono eventi per l'intera pagina web.

Tom G sopra ha creato una funzione che filtra i documenti solo per gli eventi di un dato elemento e unisce l'output di entrambi i metodi, ma presentava un difetto di duplicazione degli eventi nell'output (ed efficacemente sull'elenco interno di eventi jQuery dell'elemento che rovinava la tua applicazione). Ho risolto quel difetto e puoi trovare il codice qui sotto. Basta incollarlo nella tua console di sviluppo o nel codice dell'app ed eseguirlo quando necessario per ottenere un bel elenco di tutti gli eventi per un determinato elemento.

Ciò che è importante notare, l'elemento è in realtà HTMLElement, non l'oggetto jQuery.

function getEvents(element) {
    var elemEvents = $._data(element, "events");
    var allDocEvnts = $._data(document, "events");
    function equalEvents(evt1, evt2)
    {
        return evt1.guid === evt2.guid;
    }

    for(var evntType in allDocEvnts) {
        if(allDocEvnts.hasOwnProperty(evntType)) {
            var evts = allDocEvnts[evntType];
            for(var i = 0; i < evts.length; i++) {
                if($(element).is(evts[i].selector)) {
                    if(elemEvents == null) {
                        elemEvents = {};
                    }
                    if(!elemEvents.hasOwnProperty(evntType)) {
                        elemEvents[evntType] = [];
                    }
                    if(!elemEvents[evntType].some(function(evt) { return equalEvents(evt, evts[i]); })) {
                        elemEvents[evntType].push(evts[i]);
                    }
                }
            }
        }
    }
    return elemEvents;
}
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.