デバッグ時またはJavaScriptコードからDOMノードのイベントリスナーを見つける方法は?


841

入力ボックスと選択ボックスにいくつかのイベントリスナーが接続されているページがあります。特定のDOMノードを監視しているイベントリスナーと、そのイベントを見つける方法はありますか?

イベントは以下を使用して添付されます:

  1. プロトタイプの Event.observe ;
  2. DOM addEventListener;
  3. 要素属性としてelement.onclick

3
そもそもどうやってイベントをつけているの?ライブラリ(Prototype、jQueryなど)を使用していますか?
クレセントフレッシュ

これは、を介して複数のコールバック関数は、イベントの同じタイプに取付けることができることを注意することが重要だelement.addEventListener(type, callback, [bubble])中で、element.onclick = functionあなたが割り当てるたびに上書きされます。
ブレーデンベスト

回答:


507

ページで何が起こっているのかを調べるだけの場合は、ビジュアルイベントブックマークレットを試してみてください。

更新:利用可能なビジュアルイベント2


1
パーフェクト!FirebugのEventBugプラグインに勝る。
Robin Maben、2011

22
これにより、ページにjillion要素が追加されます。その多くは画像です。多くのイベントハンドラーがあるページでは、その有用性が大幅に低下します(私の場合、17kあり、ビジュアルイベントの読み込みに約3分かかりました)。
トニーR

15
言及されているChrome拡張機能@ssharmaは、ここで利用できるものだと
思い

1
ページがサードパーティのjsライブラリを参照している場合、Visialイベントは機能しません。エラーが発生します:XMLHttpRequestはA.com/js/jquery-ui-1.10.3.custom.js?_=1384831682813を読み込めません。Origin B.comはAccess-Control-Allow-Originでは許可されていません。
高速道路2013年

5
ChromeとFFの内部開発者ツール(F12)には、組み込みのイベントビューアがあります。Chrome:[要素]タブで、要素を選択して右に表示します:スタイル、計算済み、イベントリスナー
oriadam

365

それは、イベントがどのようにアタッチされるかによって異なります。例として、次のクリックハンドラがあるとします。

var handler = function() { alert('clicked!') };

さまざまな方法を使用して要素にアタッチします。検査を許可する方法と許可しない方法があります。

方法A)単一のイベントハンドラー

element.onclick = handler;
// inspect
alert(element.onclick); // alerts "function() { alert('clicked!') }"

方法B)複数のイベントハンドラー

if(element.addEventListener) { // DOM standard
    element.addEventListener('click', handler, false)
} else if(element.attachEvent) { // IE
    element.attachEvent('onclick', handler)
}
// cannot inspect element to find handlers

メソッドC):jQuery

$(element).click(handler);
  • 1.3.x

    // inspect
    var clickEvents = $(element).data("events").click;
    jQuery.each(clickEvents, function(key, value) {
        alert(value) // alerts "function() { alert('clicked!') }"
    })
    
  • 1.4.x(ハンドラーをオブジェクト内に格納)

    // inspect
    var clickEvents = $(element).data("events").click;
    jQuery.each(clickEvents, function(key, handlerObj) {
        alert(handlerObj.handler) // alerts "function() { alert('clicked!') }"
        // also available: handlerObj.type, handlerObj.namespace
    })
    

jQuery.fn.dataおよびを参照jQuery.data

方法D):プロトタイプ(乱雑)

$(element).observe('click', handler);
  • 1.5.x

    // inspect
    Event.observers.each(function(item) {
        if(item[0] == element) {
            alert(item[2]) // alerts "function() { alert('clicked!') }"
        }
    })
    
  • 1.6から1.6.0.3を含む(ここでは非常に難しい)

    // inspect. "_eventId" is for < 1.6.0.3 while 
    // "_prototypeEventID" was introduced in 1.6.0.3
    var clickEvents = Event.cache[element._eventId || (element._prototypeEventID || [])[0]].click;
    clickEvents.each(function(wrapper){
        alert(wrapper.handler) // alerts "function() { alert('clicked!') }"
    })
    
  • 1.6.1(少し良い)

    // inspect
    var clickEvents = element.getStorage().get('prototype_event_registry').get('click');
    clickEvents.each(function(wrapper){
        alert(wrapper.handler) // alerts "function() { alert('clicked!') }"
    })
    

3
これを更新するためのThx。残念ながら、各タイプのハンドラーを繰り返し処理する必要があります。
キースベントラップ2009

4
「方法B」(addEventListenerを)で、ここで純粋なDOMイベントAPIに登録ハンドラの列挙施設の状況についての答えだ:stackoverflow.com/questions/7810534/...
Nickolay

@ジョン:コメントをありがとう。以前に追加したリスナーを取得するための「実際のJavaScript」の例がありaddEventListenerますか?
Crescent Fresh

6
@Jan、これはjQuery 1.7.2では機能しないようですが、そのバージョンでは別のアプローチがありますか?
tomdemuyt

14
@tomdemuyt jQueryでは、イベントは.data('events')以前のようにアクセスするのではなく、内部データ配列に格納されるようになりました。内部イベントデータにアクセスするには、を使用します$._data(elem, 'events')。この関数はjQueryソースで「内部使用のみ」とマークされているため、将来も常に機能するとは限りませんが、jQuery 1.7以降は機能し、引き続き機能すると信じています。
Matt Browne

351

Chrome、Firefox、Vivaldi、SafariのgetEventListeners(domElement)デベロッパーツールコンソールでのサポート。

ほとんどのデバッグ目的で、これを使用できます。

以下は、それを使用するための非常に良いリファレンスです:https : //developers.google.com/web/tools/chrome-devtools/console/utilities#geteventlisteners


1
+1。ブラウザ固有のコードは私にとって問題ではありません。私が制御していないページを適切に機能させるためです。
Grault、2013

9
素敵ですが、Chromeコンソールのコマンドラインでのみ機能します:(
gillyspy

5
@Raghavああありがとう、使い方は違います私が最初に思ったように:)getEventListeners(object) obj getEventListeners()
jave.web

11
イベントリスナーのソースコードを取得する方法を説明していれば、3時間節約できたでしょう。その「参照」は何も説明しませんでした。他の誰かが迷子になっている場合に備えて、次の方法がありますvar list = getEventListeners(document.getElementById("YOURIDHERE")); console.log(list["focus"][0]["listener"].toString())。「フォーカス」を、検査するイベントと、同じイベントに複数のリスナーがある場合はその数に変更します。
doABarrelRoll721 2016

46
ヒント:getEventListeners($0)Chrome開発ツールでフォーカスした要素のイベントリスナーを取得します。いつも使っています。querySelector関数またはget__By_関数を使用する必要がないことを好む
cacoder

91

ChromeまたはSafariブラウザのWebKit Inspectorがこれを行うようになりました。[要素]ペインでDOM要素を選択すると、その要素のイベントリスナーが表示されます。


9
すべてのイベントハンドラが表示されるかどうかはわかりません。単一のHTMLイベントハンドラーのみ。
huyz

3
完全性のためにFirebugのEventBugプラグインについて言及する必要があります< softwareishard.com/blog/category/eventbug >
Nickolay

これはちょうど私の日を作りました、いくつかのレガシープロトタイプコードには、同じ要素の同じイベントにバインドされた複数の関数があり、それらを追跡しようとして死にかけていました。イシャンありがとうございます。
Siliconrockstar 2013

70

JavaScriptですべてのイベントリスナーをリストすることが可能です。それほど難しくはありません。prototypeHTML要素ののメソッドをハックする必要があります(リスナーを追加する前に)。

function reportIn(e){
    var a = this.lastListenerInfo[this.lastListenerInfo.length-1];
    console.log(a)
}


HTMLAnchorElement.prototype.realAddEventListener = HTMLAnchorElement.prototype.addEventListener;

HTMLAnchorElement.prototype.addEventListener = function(a,b,c){
    this.realAddEventListener(a,reportIn,c); 
    this.realAddEventListener(a,b,c); 
    if(!this.lastListenerInfo){  this.lastListenerInfo = new Array()};
    this.lastListenerInfo.push({a : a, b : b , c : c});
};

これで、すべてのアンカー要素(a)に、lastListenerInfoそのすべてのリスナーを含むプロパティがあります。そして、それは匿名関数を持つリスナーを削除するためにも機能します。


4
このメソッドは、ユーザースクリプトまたはコンテンツスクリプトを記述している場合は機能しません。最近サンドボックス化される可能性があるだけでなく、実行順序をどのように保証できますか?
huyz

このメソッドは、chrome / 19およびFF / 12で動作します。他のスクリプトの前にこれをフックすると、実行の順序が保証されます
Tzury Bar Yochay

8
Node.prototype代わりに変更することはできませんか?それはとにかくHTMLAnchorElement継承するところ.addEventListenerです。
エサイリヤ2012年

3
ユーザーエージェントがDOMホストオブジェクトのプロトタイプ継承を実装し、それらを変更できることを前提としています。どちらも良いアイデアではありません自分が所有していないオブジェクトを変更しないでください
RobG 2012年

1
これはほとんど役に立たない-どのeventListenersが追加されたかを示します。これは、場合によっては良いかもしれませんが、削除されたものではありません。したがって、削除されたものとされなかったものをデバッグしようとしている場合、単に方法はありません。
gotofritz

52

Google Chromeで getEventListenersを使用します

getEventListeners(document.getElementByID('btnlogin'));
getEventListeners($('#btnlogin'));

1
Uncaught ReferenceError:getEventListeners is not defined
Bryan Grace

3
getEventListenersは、Chromeのdevtoolsコンソールでのみ機能します。そして、これはこのより複雑な答えの複製です:stackoverflow.com/a/16544813/1026
Nickolay

41

この質問に関連するので、この質問からの回答を書き換えます。)

デバッグ時に、イベントを表示するだけの場合は、次のいずれかをお勧めします...

  1. ビジュアルイベント
  2. 要素 Chromeのデベロッパーツールのセクション:(Firefoxで同様の)右下の「イベント・リスナー」のための要素と外観を選択

コードでイベントを使用する場合で、バージョン1.8より前の jQueryを使用している場合は、以下を使用できます。

$(selector).data("events")

イベントを取得します。バージョン1.8以降、.data( "events")の使用は廃止されましたこのバグチケットを参照)。以下を使用できます。

$._data(element, "events")

別の例:コンソールへの特定のリンクのすべてのクリックイベントを書き込みます。

var $myLink = $('a.myClass');
console.log($._data($myLink[0], "events").click);

(実際の例については、http://jsfiddle.net/HmsQC/を参照してください)

残念ながら、$ ._ dataの使用は内部jQuery構造であり、将来のリリースで変更される可能性があるため、デバッグを除いてこれはお勧めできません。残念ながら、イベントにアクセスする簡単な方法は他にありません。


1
$._data(elem, "events")少なくともjQuery 1.10を使用して登録されたイベントでは、jQuery 1.10で動作しないよう$(elem).on('event', ...)です。誰かがそれらをデバッグする方法を知っていますか?
Marius Gedminas 2013

4
私はポジティブではありませんが、の最初のパラメーターは$._datajQueryオブジェクトではなく要素である必要があると思います。したがって、上記の例を次のように修正する必要がありますconsole.log($._data($myLink[0], "events").click);
Luke

29

1:Prototype.observeElement.addEventListenerを使用します(ソースコードを参照)

2:Element.addEventListener追加したリスナーを記憶するようにオーバーライドできます(EventListenerListDOM3仕様の提案から便利なプロパティが削除されました)。イベントが添付される前にこのコードを実行します。

(function() {
  Element.prototype._addEventListener = Element.prototype.addEventListener;
  Element.prototype.addEventListener = function(a,b,c) {
    this._addEventListener(a,b,c);
    if(!this.eventListenerList) this.eventListenerList = {};
    if(!this.eventListenerList[a]) this.eventListenerList[a] = [];
    this.eventListenerList[a].push(b);
  };
})();

すべてのイベントを読む:

var clicks = someElement.eventListenerList.click;
if(clicks) clicks.forEach(function(f) {
  alert("I listen to this function: "+f.toString());
});

またElement.removeEventListener、カスタムからイベントを削除するためにオーバーライドすることを忘れないでくださいElement.eventListenerList

3:Element.onclickプロパティはここで特別な注意が必要です:

if(someElement.onclick)
  alert("I also listen tho this: "+someElement.onclick.toString());

4:Element.onclickcontent属性を忘れないでください。これらは2つの異なるものです。

someElement.onclick = someHandler; // IDL attribute
someElement.setAttribute("onclick","otherHandler(event)"); // content attribute

だからあなたもそれを処理する必要があります:

var click = someElement.getAttribute("onclick");
if(click) alert("I even listen to this: "+click);

ビジュアルイベントブックマークレット(最も一般的な回答で述べられています)は、カスタムライブラリハンドラーキャッシュのみを盗みます。

特定の要素にどのイベントリスナーが接続されているかを確認するための、W3C推奨のDOMインターフェースによって提供される標準メソッドがないことがわかります。これは見落としのように見えるかもしれませんが、eventListenerListというプロパティをレベル3 DOM仕様に含めるという提案がありましたが、残念ながら後のドラフトでは削除されました。そのため、通常はアタッチされたイベントのキャッシュを維持する個々のJavascriptライブラリを参照する必要があります(後で削除して他の有用な抽象化を実行できるようにするため)。

そのため、ビジュアルイベントでイベントを表示するには、JavaScriptライブラリからイベント情報を解析できる必要があります。

要素のオーバーライドは問題になる可能性があります(つまり、JSでコーディングできないライブコレクションなどのDOM固有の機能があるため)が、eventListenerListをネイティブでサポートし、Chrome、Firefox、Operaで動作します(IE7では動作しません) )。


23

イベントリスナーを管理するためのネイティブDOMメソッドをラップして、これをの上部に配置できます<head>

<script>
    (function(w){
        var originalAdd = w.addEventListener;
        w.addEventListener = function(){
            // add your own stuff here to debug
            return originalAdd.apply(this, arguments);
        };

        var originalRemove = w.removeEventListener;
        w.removeEventListener = function(){
            // add your own stuff here to debug
            return originalRemove.apply(this, arguments);
        };
    })(window);
</script>

H / T @ les2


私が間違っている場合は修正してください。ただし、ウィンドウに接続されているイベントリスナーだけの問題ではありませんか?
Maciej Krawczyk 2017

@MaciejKrawczykうん、そしてそのバブル
Jon z

18

Firefox開発ツールがこれを行うようになりました。イベントは、jQueryDOMイベントなど、各要素の表示の右側にある「ev」ボタンをクリックすると表示されます。

インスペクタータブのFirefox開発ツールのイベントリスナーボタンのスクリーンショット


ビジュアルイベント2ブックマークレットが配線されたイベントを表示しているページのdom要素の1つを確認しましたが、右側にある小さな「ev」ボタンが表示されています。
エリック

Chromeがプラグインを必要とする一方で、FirefoxのイベントリスナーはjQuery委任イベントを検出できます。
Nick Tsai 2017

12

Firebugを使用console.dir(object or array)している場合は、を使用して、JavaScriptスカラー、配列、またはオブジェクトのコンソールログに素敵なツリーを印刷できます。

試してください:

console.dir(clickEvents);

または

console.dir(window);


10

Jan Turonの回答に基づく完全に機能するソリューション- getEventListeners()コンソールからのように動作します。

(重複には小さなバグがあります。とにかくあまり壊れません。)

(function() {
  Element.prototype._addEventListener = Element.prototype.addEventListener;
  Element.prototype.addEventListener = function(a,b,c) {
    if(c==undefined)
      c=false;
    this._addEventListener(a,b,c);
    if(!this.eventListenerList)
      this.eventListenerList = {};
    if(!this.eventListenerList[a])
      this.eventListenerList[a] = [];
    //this.removeEventListener(a,b,c); // TODO - handle duplicates..
    this.eventListenerList[a].push({listener:b,useCapture:c});
  };

  Element.prototype.getEventListeners = function(a){
    if(!this.eventListenerList)
      this.eventListenerList = {};
    if(a==undefined)
      return this.eventListenerList;
    return this.eventListenerList[a];
  };
  Element.prototype.clearEventListeners = function(a){
    if(!this.eventListenerList)
      this.eventListenerList = {};
    if(a==undefined){
      for(var x in (this.getEventListeners())) this.clearEventListeners(x);
        return;
    }
    var el = this.getEventListeners(a);
    if(el==undefined)
      return;
    for(var i = el.length - 1; i >= 0; --i) {
      var ev = el[i];
      this.removeEventListener(a, ev.listener, ev.useCapture);
    }
  };

  Element.prototype._removeEventListener = Element.prototype.removeEventListener;
  Element.prototype.removeEventListener = function(a,b,c) {
    if(c==undefined)
      c=false;
    this._removeEventListener(a,b,c);
      if(!this.eventListenerList)
        this.eventListenerList = {};
      if(!this.eventListenerList[a])
        this.eventListenerList[a] = [];

      // Find the event in the list
      for(var i=0;i<this.eventListenerList[a].length;i++){
          if(this.eventListenerList[a][i].listener==b, this.eventListenerList[a][i].useCapture==c){ // Hmm..
              this.eventListenerList[a].splice(i, 1);
              break;
          }
      }
    if(this.eventListenerList[a].length==0)
      delete this.eventListenerList[a];
  };
})();

使用法:

someElement.getEventListeners([name]) -イベントリスナーのリストを返します。名前が設定されている場合は、そのイベントのリスナーの配列を返します。

someElement.clearEventListeners([name]) -すべてのイベントリスナーを削除します(名前が設定されている場合、そのイベントのリスナーのみを削除します)


3
これは良い答えですが、bodyおよびdocument要素で機能させることができません。
David Bradshaw、

本当に素晴らしい解決策です!
Dzhakhar Ukhaev 2017年

@ピーター・モーテンセン、なぜヤンの名前を変えたのですか?:)
n00b 2017年

1
@David Bradshaw:本体、ドキュメント、ウィンドウには、Elementプロトタイプではなく独自のプロトタイプがあるため
Stefan Steiger '21

1
@ n00b:バグがあります。そういうわけで。リスナーとuseCaptionのifステートメントでコンマ演算子を使用します...コンマ演算子は、そのオペランドのそれぞれを(左から右に)評価し、最後のオペランドの値を返します。したがって、イベントのタイプに関係なく、useCaptureで一致する最初のeventListenerを削除します...コンマではなく&&にする必要があります。
Stefan Steiger 2018

8

Opera 12(最新のChrome Webkitエンジンベースではない)Dragonflyはこれをしばらく使用しており、明らかにDOM構造で表示されます。私の意見では、それは優れたデバッガであり、私がまだOpera 12ベースのバージョンを使用している唯一の理由です(v13、v14バージョンはなく、v15 WebkitベースにはまだDragonflyがありません)。

ここに画像の説明を入力してください


4

プロトタイプ1.7.1方法

function get_element_registry(element) {
    var cache = Event.cache;
    if(element === window) return 0;
    if(typeof element._prototypeUID === 'undefined') {
        element._prototypeUID = Element.Storage.UID++;
    }
    var uid =  element._prototypeUID;           
    if(!cache[uid]) cache[uid] = {element: element};
    return cache[uid];
}

4

私は最近イベントを操作していて、ページ内のすべてのイベントを表示/制御したいと思っていました。可能な解決策を検討した結果、私は独自の方法でイベントを監視するカスタムシステムを作成することにしました。だから、私は3つのことをしました。

まず、ページ内のすべてのイベントリスナーのコンテナーが必要でしたEventListeners。それがオブジェクトです。これは3つの便利なメソッドがありますadd()remove()get()

次は、私が作成したEventListenerイベントのために必要な情報を保持するオブジェクトを、すなわち:targettypecallbackoptionsuseCapturewantsUntrusted、およびメソッドを追加remove()リスナーを削除します。

最後に、ネイティブaddEventListener()removeEventListener()メソッドを拡張して、作成したオブジェクト(EventListenerおよびEventListeners)で動作するようにしました。

使用法:

var bodyClickEvent = document.body.addEventListener("click", function () {
    console.log("body click");
});

// bodyClickEvent.remove();

addEventListener()EventListenerオブジェクトを作成して追加しEventListenersEventListenerオブジェクトを返すため、後で削除できます。

EventListeners.get()ページ内のリスナーを表示するために使用できます。EventTargetまたは文字列(イベントタイプ)を受け入れます。

// EventListeners.get(document.body);
// EventListeners.get("click");

デモ

この現在のページのすべてのイベントリスナーを知りたいとしましょう。私たちはそれを行うことができます(この場合、スクリプトマネージャー拡張機能、Tampermonkeyを使用している場合)。次のスクリプトはこれを行います:

// ==UserScript==
// @name         New Userscript
// @namespace    http://tampermonkey.net/
// @version      0.1
// @description  try to take over the world!
// @author       You
// @include      https://stackoverflow.com/*
// @grant        none
// ==/UserScript==

(function() {
    fetch("https://raw.githubusercontent.com/akinuri/js-lib/master/EventListener.js")
        .then(function (response) {
            return response.text();
        })
        .then(function (text) {
            eval(text);
            window.EventListeners = EventListeners;
        });
})(window);

すべてのリスナーをリストすると、299のイベントリスナーがあると表示されます。重複しているように見えますが、実際に重複しているかどうかはわかりません。すべてのイベントタイプが複製されるわけではないため、これらの「複製」はすべて個別のリスナーである可能性があります。

このページのすべてのイベントリスナーを一覧表示するコンソールのスクリーンショット

コードは私のリポジトリにあります。かなり長いので投稿したくありませんでした。


更新:これはjQueryでは機​​能しないようです。EventListenerを調べると、コールバックが

function(b){return"undefined"!=typeof r&&r.event.triggered!==b.type?r.event.dispatch.apply(a,arguments):void 0}

これはjQueryに属し、実際のコールバックではないと思います。jQueryは、実際のコールバックをEventTargetのプロパティに格納します。

$(document.body).click(function () {
    console.log("jquery click");
});

ここに画像の説明を入力してください

イベントリスナーを削除するには、実際のコールバックをremoveEventListener()メソッドに渡す必要があります。したがって、jQueryでこれを機能させるには、さらに変更する必要があります。将来は修正するかもしれません。


よく働く!ありがとう
mt025

3

私はjQuery 2.1でそれを実行しようとしていますが、 " $().click() -> $(element).data("events").click;"メソッドでは機能しません。

私の場合、$ ._ data()関数のみが機能することに気付きました:

	$(document).ready(function(){

		var node = $('body');
		
        // Bind 3 events to body click
		node.click(function(e) { alert('hello');  })
			.click(function(e) { alert('bye');  })
			.click(fun_1);

        // Inspect the events of body
		var events = $._data(node[0], "events").click;
		var ev1 = events[0].handler // -> function(e) { alert('hello')
		var ev2 = events[1].handler // -> function(e) { alert('bye')
		var ev3 = events[2].handler // -> function fun_1()
        
		$('body')
			.append('<p> Event1 = ' + eval(ev1).toString() + '</p>')
			.append('<p> Event2 = ' + eval(ev2).toString() + '</p>')
			.append('<p> Event3 = ' + eval(ev3).toString() + '</p>');        
	
	});

	function fun_1() {
		var txt = 'text del missatge';	 
		alert(txt);
	}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>

<body>
</body>



1

これらの関数を変更すると、追加されたリスナーをログに記録できます。

EventTarget.prototype.addEventListener
EventTarget.prototype.attachEvent
EventTarget.prototype.removeEventListener
EventTarget.prototype.detachEvent

残りのリスナーを

console.log(someElement.onclick);
console.log(someElement.getAttribute("onclick"));
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.