web-dev-qa-db-ja.com

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

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

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

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

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

更新 ビジュアルイベント2 available;

489
Andrew Hedges

イベントがどのように関連付けられているかによって異なります。説明のために、次のクリックハンドラがあるとします。

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!') }"
    })
    
353
Crescent Fresh

Chrome、Firefox、Vivaldi、およびSafariは、Developer ToolsコンソールでgetEventListeners(domElement)をサポートしています。

デバッグ目的の大部分では、これを使用できます。

以下はそれを使用するための非常に良い参考資料です: https://developers.google.com/chrome-developer-tools/docs/commandline-api#geteventlistenersobject

249
Raghav

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

85
Ishan

すべてのイベントリスナを一覧表示することは可能です JavaScriptで:それほど難しくありません。 HTML要素のprototypeメソッドをハックするだけです( before リスナーの追加)。

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プロパティを持ちます。匿名関数を使ってリスナーを削除することもできます。

67

Google Chrome :でgetEventListenerを使用します。

getEventListeners(document.getElementByID('btnlogin'));
getEventListeners($('#btnlogin'));
43
Pranay Soni

(これはここで関連しているので、 this question から答えを書き換えてください。)

デバッグ時にイベントを見たいだけなら、どちらかをお勧めします。

  1. ビジュアルイベント
  2. Chromeの開発者ツールのElementsセクション:要素を選択して右下にある「イベントリスナー」を探します(Firefoxでも同様)

自分のコードでイベントを使用したいが、jQuery バージョン1.8より前を使用している場合は、次のように使用できます。

$(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の内部構造であり将来のリリースで変更される可能性があるため、デバッグを除いて推奨されません 。残念ながら、他の簡単な方法でイベントにアクセスする方法はありません。

41
Luke

1:Prototype.observeはElement.addEventListenerを使用します( ソースコードを参照

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

(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.onclickのcontent属性を忘れないでください。これらは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);

Visual Eventのブックマークレット(最も一般的な回答で言及されています)は、カスタムライブラリハンドラのキャッシュを盗むだけです。

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

そのため、Visual Eventがイベントを表示するには、Javascriptライブラリからイベント情報を解析できなければなりません。

要素のオーバーライドは疑わしいかもしれません(つまり、ライブコレクションのような、JSではコーディングできないDOM固有の機能がいくつかあるからです)が、eventListenerListのサポートはネイティブであり、Chrome、Firefox、およびOperaでは機能します(IE7では機能しません)。 ).

25
Jan Turoň

これをあなたの<head>の先頭に置くことで、イベントリスナーを管理するためのネイティブDOMメソッドをラップすることができます。

<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

21
Jon z

Firefox開発者ツールがこれを行います。イベントは、 jQuery および _ dom _ eventsを含む、各要素の表示の右側にある[ev]ボタンをクリックすると表示されます。

Screenshot of Firefox developer tools' event listener button in the inspector tab

18
simonzack

Firebug がある場合は、JavaScriptのスカラ、配列、またはオブジェクトのコンソールログにNiceツリーを出力するためにconsole.dir(object or array)を使用できます。

試してください:

console.dir(clickEvents);

または

console.dir(window);
12
Michael Butler

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]) - nameが設定されている場合、イベントリスナのリストを返します、そのイベントのリスナの配列を返します

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

8
n00b

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

enter image description here

8

プロトタイプ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
Ronald

NicejQuery Eventsエクステンションが存在します。

enter image description here (トピック ソース

3
T.Todua

私は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>
2
Joel Barba

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

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

リスナーの残りの部分を

console.log(someElement.onclick);
console.log(someElement.getAttribute("onclick"));
0
Aiden Waterman

私は最近イベントに取り組んでいて、ページ内のすべてのイベントを表示/制御したいと思いました。考えられる解決策を検討した結果、私は自分のやり方でイベントを監視するためのカスタムシステムを作成することにしました。それで、私は3つのことをしました。

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

次に、イベントに必要な情報(EventListenertargettypecallbackoptionsuseCapture)を保持するwantsUntrustedオブジェクトを作成し、リスナーを削除するためのメソッドremove()を追加しました。

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

使用法:

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

// bodyClickEvent.remove();

addEventListener()EventListenerオブジェクトを作成し、それをEventListenersに追加してEventListenerオブジェクトを返すので、後で削除できます。

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のイベントリスナーがいることがわかります。いくつかの重複があるようですが、それらが本当に重複しているかどうかはわかりません。すべてのイベントタイプが重複しているわけではないので、それらの「重複している」すべてが個々のリスナーになる可能性があります。

screenshot of console listing all event listeners in this page

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


更新: これは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");
});

enter image description here

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

0
akinuri