jQueryはオブジェクトに登録されたイベントハンドラーを検索します


555

オブジェクトに登録されているイベントハンドラを見つける必要があります。

例えば:

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

$("#el")クリックマウスオーバーが登録されています

それを見つけて、おそらくイベントハンドラを反復する関数はありますか?

適切なメソッドを介してjQueryオブジェクトでそれができない場合、プレーンなDOMオブジェクトで可能ですか?


5
残念ながら、今:bugs.jquery.com/ticket/10589
Skylar Saveland

2
1.8前後のjQueryの両方をサポート:var events = (jQuery._data || jQuery.data)(elem, 'events');
oriadam

2
FFおよびChrome開発ツール(F12)を使用して、これらのイベントリスナーを表示できることに注意してください。参照developers.google.com/web/tools/chrome-devtools/debug/...developer.mozilla.org/en-US/docs/Tools/Page_Inspector/How_to/...
oriadam

回答:


691

jQuery 1.8以降、データの「パブリックAPI」からイベントデータを利用できなくなりました。このjQueryブログ投稿を読んでください。代わりにこれを使用する必要があります:

jQuery._data( elem, "events" );

elem jQueryオブジェクトやセレクターではなく、HTML要素である必要があります。

これは内部の「プライベート」構造であり、変更しないでください。これはデバッグ目的でのみ使用してください。

古いバージョンのjQueryでは、次の古いメソッドを使用する必要がある場合があります。

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

222
ただし、引き続き使用できます $._data($(elem).get(0), "events")
ブルガレ2012

10
blog.jquery.com/2011/11/08/building-a-slimmer-jquery .data(“ events”):jQueryは、そのイベント関連データを、各要素の(待機する)イベントという名前のデータオブジェクトに格納します。これは内部データ構造であるため、1.8ではユーザーデータ名前空間から削除されるため、同じ名前の項目と競合しません。jQueryのイベントデータは引き続きjQuery._data(element、 "events")を介してアクセスできますが、これはドキュメント化されていない内部データ構造であり、変更しないでください。
Sam Greenhalgh、2012

私はこのメソッドを使用して、ボタンのクリックイベントを見つけ出しています。Chromeコンソールではhandler: function () {、クリックプロパティ内に表示されていました。関数部分をダブルクリックして展開し、関数の全内容を表示する必要がありました。
ジム

@jimはい、ダブルクリックが答えです
Adib Aroui

2
シームレスに両方のオプションをサポートしていますvar events = (jQuery._data || jQuery.data)(elem, 'events');
oriadam

84

次のように、(jQuery 1.8以降の)イベントをクロールすることで実行できます。

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

ここにあなたが遊ぶことができる例があります:

$(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
これが正解です。重要なビットは後半です。これにより、すべてのコードを検索しなければならない場合に1時間以上かかっていた問題を1分未満で見つけることができました。ありがとうございました!
Andrew Ensley、

2
1.4で動作しますが、jQuery 1.8.2では動作しません。
TimoKähkönen12年

15
jQuery 1.8以降の場合、「パブリックデータ」メソッドの代わりに「プライベートデータ」メソッドを使用する必要あります。オブジェクトが実際に格納されていない長い時間のために、私たちは、「パブリックAPI」からこの「プロキシ」を除去することにより、コードの数バイトをトリミングjQuery._data( jQuery("#el")[0], "events" );jQuery("#el").data("events")events.data()
gnarf

36

jQuery 1.8以降では、内部データが別のオブジェクトに配置されるため、これは機能しなくなります。

最新の非公式(ただし、以前のバージョンでも機能しますが、少なくとも1.7.2では機能します)の方法は次のとおりです- $._data(element, "events")

下線( "_")は、ここで違いを生むものです。内部的にはを呼び出して$.data(element, name, null, true)おり、最後(4番目)のパラメーターは内部パラメーター( "pvt")です。


$ ._ data( "body"、 "events")未定義$()。jquery; "1.7.1"(1.7.2および1.8.1は常に "未定義"です)
Mars Robertson

2
@Michal-api.jquery.com/ jQuery.dataは、セレクタではなく要素を受け入れると言っています。
PhistucK 2012

1
正常に動作するようになりました:$ ._ data($( "body")。get(0)、 "events")またはさらに良い:$( "body")。data( "events")!
Mars Robertson

2
FWIW-特に文書化していないパラメーターを使用して、他のデータ関数を「内部で」呼び出すことを指摘すると、おそらく必要ありません。しかし、はい、jQuery._data( element, "events" )この情報を取得する「正しい」方法です。
gnarf 2013年

34

恥知らずなプラグインですが、findHandlerJSを使用できます

これを使用するには、findHandlersJSをインクルードする(または、未加工のJavaScriptコードChromeのコンソールウィンドウにコピーして貼り付ける)必要がある要素のイベントタイプとjqueryセレクターを指定するだけです。

あなたの例では、次のようにして、あなたが言及したイベントハンドラをすばやく見つけることができます

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

これは返されるものです:

  • element
    イベントハンドラが登録された実際の要素

  • 関心のあるイベントタイプ(クリック、変更など)のjqueryイベントハンドラーに関する情報を含むevents 配列
    • ハンドラー
      右クリックして[関数定義の表示]を選択すると表示される実際のイベントハンドラーメソッド
    • selector
      委任されたイベントに提供されるセレクター。直接イベントの場合は空になります。
    • ターゲット
      このイベントハンドラーがターゲットとする要素のリスト。たとえば、ドキュメントオブジェクトに登録され、ページ内のすべてのボタンを対象とする委任イベントハンドラの場合、このプロパティはページ内のすべてのボタンをリストします。それらにカーソルを合わせると、クロムで強調表示されます。

ここで試すことができます


それが受け入れられるべき答えだと思います。それも私のために働く唯一のものです。イベントを検索するすべての要素を通過するので、非常に徹底しています。
Marquinho Peli

12

私はこの目的のために、firebugにeventbugプラグインを使用します。


ありがとう、素晴らしいヒント。拡張機能は、ページのイベントを表示するタブをFirebug(「イベント」)に追加するため、簡単にイベントを調べることができます。
グルーバー

11
また、Chromeデベロッパーツールの[要素]タブに[イベントリスナー]があり、[ソース]タブに[イベントリスナーブレークポイント]があります。
clayzermk1

10

@jpsの両方のソリューションを1つの関数に結合しました。

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

ただし、この関数はjQuery自体を使用して設定されたイベントのみを返すことができます。


5

1.9以降、Migrateプラグインを使用して古い動作を復元する以外に、イベントを取得するための文書化された方法はありません。jpsが言及するように_.data()メソッドを使用できますが、これは内部メソッドです。したがって、この機能が必要な場合は、正しいことを実行し、移行プラグインを使用してください。

上のjQueryドキュメントから .data("events")

1.9より前のバージョンでは、.data( "events")を使用して、jeventのドキュメント化されていない内部イベントデータ構造を要素に対して取得することができました。この特別なケースは1.9で削除されました。この内部データ構造を取得するためのパブリックインターフェイスはなく、ドキュメント化されていません。ただし、jQuery Migrateプラグインは、それに依存するコードのこの動作を復元します。


受け入れられた回答は、最近のバージョンでそれを取得するための新しい正しい方法も明確に示しています:jQuery._data( elem, "events" );...
Ian

2
文書化されていないプライベートな方法は、決して正しい方法ではありません。文書化され、公開され、意図された正しい方法は、移行プラグインを使用することです。
オリゴフレン2013年

3
Migrateプラグインのポイントを誤解しているようです。jQueryは非推奨の機能を削除しました。Migrateプラグインは、開発者のコ​​ードを新しいバージョンに移行して、機能を失うことなくすぐに新しい機能や改善を利用できるようにするためのものです。これは、新しいバージョンのjQueryを適切に使用するために、コーダーが何をする必要があるかを理解するのに役立ちます。本番環境で機能を復元するために使用しないでください。また、jQueryのドキュメントには多くのものが文書化されておらず、最新の状態ではありません。それらは以前に指摘されているため、理由ではありません
Ian

また、jQueryブログに提案として含まれている場合は、次のように使用します:blog.jquery.com/2012/08/09/jquery-1-8-released
Ian

Migrateプラグインに対するあなたの推論は合理的であるようです。回答を削除してもよろしいですか?
オリゴフレン2013年

5

要素のイベントを確認するには:

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

これは直接イベントハンドラーでのみ機能することに注意してください。$(document).on( "event-name"、 "jq-selector"、function(){// logic})を使用している場合は、この回答の下部にあるgetEvents関数

例えば:

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

または

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

完全な例:

<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でインストールされる動的リスナーを含む、より完全なチェック方法

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

使用例:

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

このgetEvents方法は全体的に素晴らしいですが、問題はIE11で重複したエントリを提供することです(私も知っていますが、IEは企業ですが...)。編集:FFには何も含まれていませんが、$ ._ dataには要素の重複イベントが含まれています...奇妙なIEの世界。ただし、イベントが重複するこの可能性に注意することが重要です。
ドミニクシマスキ

ああ、トム、このメソッドを実行するたびにイベントが増加するのは、実際にはコードです。良くない。
ドミニクシマスキ

4

割り当てられたイベントハンドラーのjQueryのキャッシュと、それらを追加するためのネイティブメソッドを使用する要素の両方をチェックするカスタムjQueryセレクターを作成しました。

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

例:

$(":event(click)")

これにより、クリックハンドラーがアタッチされている要素が返されます。


2

ECMAScript 5.1 /を搭載した最新のブラウザではArray.prototype.map

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

ブラウザーのコンソールで、ハンドラーのソースをカンマ区切りで出力します。特定のイベントで何が実行されているかを一目で確認するのに役立ちます。


jQuery._data('ct100_ContentPlaceHolder1_lcsSection','events')["EVENT_NAME"].map(function(elem){return elem.handler;}); Uncaught TypeError:<anonymous>:1:62に未定義のプロパティ 'EVENT_NAME'を読み取れません
Mike W

'ct100_ContentPlaceHolder1_lcsSection'DOM要素ではなく文字列です。
Jesan Fafon 2017年

2

イベントは以下を使用して取得できます。

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

またはjQuery 1.8以降:

jQuery._data(elem, 'events');

注: を使用してバインドされたイベントは、以下を使用して$('selector').live('event', handler) 取得できます。

jQuery(document).data('events')

2
jQuery(document).data( 'events')は未定義
Mike W

1

答えの多くは興味深いと言わざるを得ませんが、最近は同様の問題があり、DOMを使用することで解決策は非常に簡単になりました。繰り返すのではなく、必要なイベントを直接狙うので違いますが、以下に、より一般的な答えを示します。

私は一列に画像を持っていました:

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

そして、その画像にはクリックイベントハンドラーがアタッチされています。

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

私の意図はクリック可能な領域を行全体に拡大することだったので、最初にすべての画像と相対行を取得しました。

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

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

さて、実際の回答行では、次のようにして、元の質問に答えます。

tr.click(this.onclick);

そこで、DOM要素から直接イベントハンドラーをフェッチして、jQueryクリックイベントハンドラーに配置しました。魅力のように機能します。

さて、一般的なケースに。jQuery以前の時代には、Douglas Crockfordから私たちの定命の者に贈られた2つのシンプルで強力な関数を使用して、すべてのイベントをオブジェクトにアタッチできました。

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

これを行う別の方法は、jQueryを使用して要素を取得し、実際のJavascriptを実行してイベントハンドラーを取得および設定し、再生することです。例えば:

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

1
jQueryはイベント処理の最適化を行うと思いますが、これはあなたのコードによってここで回避されていると思います。
エミールベルジェロン

おかげで、ええ、これはハッキーだと感じました-その最適化についてもっと学ぶための良いリンクはありますか?
tempranova

0

上記の回答のいくつかを組み合わせて、このクレイジーな見た目で機能的なスクリプトを作成しました。このスクリプトは、指定された要素のイベントリスナーのほとんどを一覧表示することを期待しています。ここで自由に最適化してください。

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では、特定の要素のイベントに単にアクセスすることはできません。文書化されていない内部メソッドを使用してそれらにアクセスできます

$._data(element, "events")

しかし、それでもまだすべてのイベントが表示されるわけではありません。正確には、割り当てられたイベントは表示されません

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

これらのイベントはドキュメント内に保存されるため、ブラウジングして取得できます

$._data(document, "events")

しかし、ウェブページ全体のイベントがあるので、それは大変な作業です。

上記のトムGは、特定の要素のイベントのみを対象にドキュメントをフィルタリングし、両方のメソッドの出力をマージする関数を作成しましたが、出力にイベントを複製するという欠点がありました(そして、要素のjQuery内部イベントリストがアプリケーションと混ざっています)。私はその欠陥を修正し、以下のコードを見つけることができます。それを開発コンソールまたはアプリのコードに貼り付け、必要に応じて実行して、特定の要素のすべてのイベントの一覧を取得します。

注意すべき重要なことは、要素は実際にはjQueryオブジェクトではなくHTMLElementです。

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;
}
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.