jQuery bir nesneye kayıtlı olay işleyicilerini bulur


555

Bir nesne üzerinde hangi olay işleyicilerinin kayıtlı olduğunu bulmam gerekiyor.

Örneğin:

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

$("#el")gelmiştir tıklayın ve mouseover kayıtlı.

Bunu bulmak ve muhtemelen olay işleyicileri üzerinde yineleme yapmak için bir işlev var mı?

Bir jQuery nesnesinde uygun yöntemler ile mümkün değilse, düz bir DOM nesnesinde mümkün mü?



2
hem jQuery öncesi ve sonrası destek 1.8:var events = (jQuery._data || jQuery.data)(elem, 'events');
oriadam

2
Bu olay dinleyicilerini görmek için FF ve Chrome geliştirici araçlarını (F12) kullanabileceğinizi unutmayın. Bkz developers.google.com/web/tools/chrome-devtools/debug/... ve developer.mozilla.org/en-US/docs/Tools/Page_Inspector/How_to/...
oriadam

Yanıtlar:


691

JQuery 1.8'den itibaren, olay verileri artık veriler için "genel API" dan kullanılamamaktadır. Bu jQuery blog gönderisini okuyun . Şimdi bunun yerine şunu kullanmalısınız:

jQuery._data( elem, "events" );

elem jQuery nesnesi veya seçici değil, bir HTML Öğesi olmalıdır.

Lütfen bunun dahili, 'özel' bir yapı olduğunu ve değiştirilmemesi gerektiğini unutmayın. Bunu yalnızca hata ayıklama amacıyla kullanın.

JQuery'nin daha eski sürümlerinde, şu eski yöntemi kullanmanız gerekebilir:

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

222
ama yine de kullanabilirsiniz $._data($(elem).get(0), "events")
bullgare

10
blog.jquery.com/2011/11/08/building-a-slimmer-jquery .data (“events”): jQuery, etkinlikle ilgili verilerini her öğedeki (bekle) olaylar adlı bir veri nesnesinde depolar. Bu bir iç veri yapısıdır, bu nedenle 1.8'de bu, kullanıcı veri adı alanından kaldırılacaktır, böylece aynı ada sahip öğelerle çakışmayacaktır. jQuery'nin etkinlik verilerine hala jQuery._data (element, "events") üzerinden erişilebilir, ancak bunun belgelenmemiş ve değiştirilmemesi gereken bir iç veri yapısı olduğunu unutmayın.
Sam Greenhalgh

Bir düğmenin tıklama etkinliğini öğrenmek ve denemek için bu yöntemi kullanıyorum. Chrome konsolunda handler: function () {click özelliğinin içinde gösterildi. Fonksiyonun tüm içeriğini genişletmek ve göstermek için fonksiyon kısmına çift tıklamak zorunda kaldım.
Jim

@jim yeaaah, çift tıklama cevaptır
Adib Aroui

2
Her iki seçeneği de sorunsuz bir şekilde destekleyin:var events = (jQuery._data || jQuery.data)(elem, 'events');
oriadam

84

Olayları (jQuery 1.8+ sürümünden itibaren) tarayarak bunu yapabilirsiniz:

$.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
  });
});

İşte oynayabileceğiniz bir örnek:

$(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
Bu doğru cevap. Kritik bit ikinci yarıdır. Bu, tüm kodu aramak zorunda olsaydım bir saatten kısa bir süre içinde bir sorun bulmama yardımcı oldu. Teşekkür ederim!
Andrew Ensley

2
1.4 ile çalışır, ancak jQuery 1.8.2 ile çalışmaz.
Timo Kähkönen

15
JQuery 1.8+ için, gereken 'özel veri' yöntemi kullanın: jQuery._data( jQuery("#el")[0], "events" );yerine 'kamu veri' yönteminin: jQuery("#el").data("events"). eventsNesne aslında saklanan edilmemiştir .data()uzun süre, biz "kamu API" Bu "vekil" kaldırarak birkaç kod bayt dışarı kesilmiş
gnarf

36

JQuery 1.8+ için, dahili veriler farklı bir nesneye yerleştirildiği için bu artık çalışmaz.

En son gayri resmi (ancak önceki sürümlerde de çalışıyor, en azından 1.7.2'de) şimdi yapmanın yolu - $._data(element, "events")

Burada fark yaratan alt çizgi ("_"). Dahili olarak, $.data(element, name, null, true)son (dördüncü) parametre dahili bir parametredir ("pvt").


$ ._ data ("gövde", "olaylar") undefined $ (). jquery; "1.7.1" (1.7.2 ve 1.8.1 her zaman denendi "tanımsız")
Mars Robertson

2
@Michal - api.jquery.com/jQuery.data bir seçici değil, bir öğeyi kabul ettiğini söylüyor.
PhistucK

1
Şimdi iyi çalışıyor: $ ._ data ($ ("body"). Get (0), "events") Ya da daha iyisi: $ ("body"). Data ("events")!
Mars Robertson

2
FWIW - 'Dahili olarak' diğer veri işlevini, özellikle belgelemediğimiz bir parametreyle çağırdığını belirtmek, muhtemelen gerekli değildir. Ama evet, jQuery._data( element, "events" )bu bilgiyi şimdi almanın 'doğru' yolu.
13'te gnarf

34

Utanmaz fiş, ancak findHandlerJS'yi kullanabilirsiniz

Bunu kullanmak için findHandlersJS'yi eklemeniz (veya yalnızca çiğ javascript kodunu krom konsol penceresine kopyalayıp yapıştırmanız ) ve ilgilendiğiniz öğeler için etkinlik türünü ve bir jquery seçiciyi belirtmeniz gerekir.

Örneğiniz için, bahsettiğiniz olay işleyicilerini hızlıca bulabilirsiniz

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

İade edilen budur:

  • element
    Olay işleyicinin kayıtlı olduğu gerçek eleman
  • events
    İlgilendiğimiz etkinlik türü için jquery olay işleyicileri hakkında bilgi içeren dizi (ör. tıklama, değiştirme vb.)
    • handler
      Sağ tıklayarak ve İşlev tanımını göster'i seçerek görebileceğiniz gerçek olay işleyici yöntemi
    • seçici
      Temsilci seçili etkinlikler için sağlanan seçici. Doğrudan etkinlikler için boş olacaktır.
    • hedefler
      Bu olay işleyicinin hedeflediği öğelerle listele. Örneğin, belge nesnesine kaydedilen ve bir sayfadaki tüm düğmeleri hedefleyen yetkilendirilmiş bir olay işleyicisi için bu özellik sayfadaki tüm düğmeleri listeler. Bunları üzerine getirebilir ve kromda vurgulanmış olarak görebilirsiniz.

Burada deneyebilirsin


Bunun kabul edilen cevap olması gerektiğini düşünüyorum. Benim için de işe yarayan tek kişi bu. Olayları arayan tüm unsurlardan geçtiği için çok kapsamlı.
Marquinho Peli

12

Bu amaçla kundakçı için eventbug eklentisini kullanıyorum .


Teşekkürler, harika bir ipucu. Uzantı, Firebug'a ("Etkinlikler") sayfanın etkinliklerini gösteren bir sekme ekler, böylece bunları kolayca dışa aktarabilirsiniz.
Gruber

11
Ayrıca, Chrome Geliştirici Araçları'nda "Öğeler" sekmesi altında "Etkinlik Dinleyicileri" ve "Kaynaklar" sekmesi altında "Etkinlik Dinleyici Kesme Noktaları" bulunur.
clayzermk1

10

@Jps her iki çözümü de bir fonksiyona birleştirdim:

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 {};
};

Ancak dikkat edin, bu işlev yalnızca jQuery kullanılarak ayarlanan olayları döndürebilir.


5

1.9 itibariyle, eski davranışı geri yüklemek için Migrate eklentisini kullanmak dışında olayları almanın belgelenmiş bir yolu yoktur. _.Data () yöntemini jps'den bahsedebilirsiniz, ancak bu dahili bir yöntemdir. Bu nedenle, doğru olanı yapın ve bu işlevselliğe ihtiyacınız varsa Migrate eklentisini kullanın.

Üzerindeki jQuery belgelerinden .data("events")

1.9'dan önce .data ("events"), başka bir kod "events" adında bir veri öğesi tanımlamamışsa, bir öğe için jQuery'nin belgelenmemiş dahili olay veri yapısını almak için kullanılabilir. Bu özel durum 1.9'da kaldırıldı. Bu dahili veri yapısını geri almak için herkese açık bir arabirim yoktur ve dokümantasyona tabi değildir. Ancak, jQuery Migrate eklentisi, ona bağlı olan kod için bu davranışı geri yükler.


Kabul edilen cevap ayrıca son sürümler için yeni, doğru yolu gösteriyor : jQuery._data( elem, "events" );...
Ian

2
Özel, belgesiz bir yol asla doğru bir yol olmaz. Doğru şekilde - belgelenmiş, herkese açık ve amaçlanan - Migrate eklentisini kullanmaktır.
oligofren

3
Migrate eklentisinin noktasını yanlış anlamış görünüyorsunuz. jQuery kullanımdan kaldırılan özellikleri kaldırdı ve Migrate eklentisi, geliştiricinin kodunu yeni sürümlere geçirmeye yardımcı olmak , böylece yeni özelliklerden ve iyileştirmelerden hemen yararlanabilmelerini ancak işlevselliğini kaybetmemelerini sağlamaktır. Kodlayıcının jQuery'nin yeni sürümlerini doğru bir şekilde kullanmaya başlamak için ne yapması gerektiğini görmesine yardımcı olması amaçlanmıştır. Özellikleri geri yüklemek için üretimde kullanmamalısınız . Ayrıca, jQuery belgelerinde pek çok şey belgelenmemiş ve güncel değil - daha önce işaret ettiler, bu bir sebep değil
Ian

Ayrıca, jQuery blogunda bir öneri olarak dahil edilirse, onu kullanırım: blog.jquery.com/2012/08/09/jquery-1-8-released
Ian

Migrate eklentisi hakkındaki mantık makul görünüyor. Cevabımı silersem tamam mı?
oligofren

5

Bir öğedeki olayları kontrol etmek için:

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

Bunun yalnızca doğrudan olay işleyicileriyle çalışacağını, $ (document) .on ("event-name", "jq-selector", function () {// logic}) kullanıyorsanız, Bu cevabın altındaki getEvents işlevi

Örneğin:

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

veya

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

Tam Örnek:

<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>

$ (Document) .on ile yüklenen dinamik dinleyicileri içeren daha eksiksiz bir kontrol yöntemi.

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;
}

Örnek kullanım:

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

Bu getEventsyöntem çok büyük, ama şey, IE11 yinelenen girişler verir (biliyorum, IE tekrar, ama kurumsal buna ihtiyacı var ...). EDIT: $ ._ veri öğe için yinelenen olaylar içeriyor, FF herhangi bir içermese de ... Tuhaf IE dünya. Ancak, yinelenen etkinliklere sahip olma olasılığına dikkat etmek önemlidir.
Dominik Szymański

Oh, Tom, aslında bu yöntemin her yürütmesiyle olayları çarpan kodunuz. İyi değil.
Dominik Szymański

4

Hem jQuery'nin atanmış olay işleyicileri önbelleğine hem de bunları eklemek için yerel yöntemi kullanan öğelere karşı kontrol eden özel bir jQuery seçici oluşturdum:

(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);

Misal:

$(":event(click)")

Bu, kendilerine bağlı bir tıklama işleyicisi olan öğeleri döndürür.


2

ECMAScript 5.1 / ile modern bir tarayıcıda Array.prototype.map,

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

tarayıcı konsolunuzda, işleyicilerin kaynağını yazdıracak, virgülle ayrılmış. Belirli bir etkinlikte neyin çalıştığına bakmak için kullanışlıdır.


jQuery._data('ct100_ContentPlaceHolder1_lcsSection','events')["EVENT_NAME"].map(function(elem){return elem.handler;}); Yakalanmayan TypeError: <anonymous> konumunda tanımlanmamış 'EVENT_NAME' mülkü okunamıyor: 1: 62
Mike W

'ct100_ContentPlaceHolder1_lcsSection'bir DOM Öğesi değil, bir dizedir.
Jesan Fafon

2

Olaylar aşağıdakiler kullanılarak alınabilir:

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

veya jQuery 1.8+:

jQuery._data(elem, 'events');

Not: Kullanarak sınırlanan etkinlikler $('selector').live('event', handler) aşağıdakiler kullanılarak alınabilir:

jQuery(document).data('events')

2
jQuery (document) .data ('events') bana undefined veriyor
Mike W

1

Cevapların birçoğunun ilginç olduğunu söylemeliyim, ancak son zamanlarda benzer bir sorunum vardı ve çözüm DOM yoluna giderek son derece basitti. Farklıdır, çünkü yinelemezsiniz, ancak doğrudan ihtiyacınız olan olayı hedeflersiniz, ancak aşağıda daha genel bir cevap vereceğim.

Arka arkaya bir görüntü vardı:

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

Ve bu görselin kendisine bir tıklama olay işleyicisi eklenmişti:

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

Amacım tıklanabilir alanı tüm satıra genişletmekti, bu yüzden önce tüm resimleri ve göreli satırları aldım:

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

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

Şimdi asıl anwer hattında asıl soruya bir cevap vererek aşağıdaki gibi yaptım:

tr.click(this.onclick);

Böylece olay işleyicisini doğrudan DOM öğesinden aldım ve jQuery click olay işleyicisine koydum. Tıkır tıkır çalışıyor.

Şimdi, genel duruma. Eski jQuery günlerinde tüm olayları Douglas Crockford'un ölümlülerine hediye ettiği iki basit ama güçlü fonksiyonla bir nesneye bağlayabilirsiniz :

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

Bunu yapmanın başka bir yolu, sadece öğeyi almak için jQuery kullanmak, daha sonra almak ve ayarlamak ve olay işleyicileri ile oynamak için gerçek Javascript geçmektir. Örneğin:

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

1
Ben jQuery burada kod tarafından atlanmış olduğunu düşünüyorum olay işleme optimizasyonu yaptığını düşünüyorum.
Emile Bergeron

Teşekkürler, evet bunun kibirli olduğunu hissettim - bu optimizasyon hakkında daha fazla bilgi edinmek için iyi bir bağlantı var mı?
tempranova

0

Yukarıdaki cevapların bazılarını birleştirdim ve bu öğedeki olay dinleyicilerinin çoğunu listeleyen bu çılgın görünümlü ama işlevsel komut dosyasını oluşturdum. Burada optimizasyon yapmaktan çekinmeyin.

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, yalnızca belirli bir öğenin etkinliklerine erişmenize izin vermez. Belgelenmemiş dahili yöntemi kullanarak bunlara erişebilirsiniz

$._data(element, "events")

Ama yine de size tüm olayları vermeyecek, kesin olarak size atanan olayları göstermeyecek

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

Bu olaylar belgenin içinde saklanır, böylece göz atarak bunları alabilirsiniz

$._data(document, "events")

ancak tüm web sayfası için etkinlikler olduğu için bu zor bir iştir.

Yukarıdaki Tom G, belgeyi yalnızca belirli bir öğenin olayları için filtreleyen ve her iki yöntemin çıktısını birleştiren bir işlev oluşturdu, ancak çıktıda yinelenen olayların bir kusuru vardı (ve etkin olarak öğenin uygulamanızla mesajlaşmasını sağlayan jQuery dahili olay listesi üzerinde). Bu kusuru düzelttim ve kodu aşağıda bulabilirsiniz. Belirli bir öğeye ilişkin tüm etkinliklerin güzel bir listesini almak için gerektiğinde geliştirici konsolunuza veya uygulama kodunuza yapıştırın ve gerektiğinde çalıştırın.

Dikkat edilmesi gereken önemli olan öğe, jQuery nesnesi değil aslında HTMLElement'dir.

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;
}
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.