如何在调试时或从JavaScript代码中在DOM节点上查找事件侦听器?

How to find event listeners on a DOM node when debugging or from the JavaScript code?

我有一个页面,其中一些事件监听器连接到输入框和选择框。有没有一种方法可以查明哪些事件监听器正在观察特定的DOM节点以及哪些事件?

事件附加使用:

  • 原型的Event.observe
  • 多姆的addEventListener
  • 作为元素属性element.onclick

  • 如果你只需要检查页面上发生了什么,你可以试试可视事件书签。

    更新:可视事件2可用;


    这取决于事件的附加方式。对于示例,假设我们有以下单击处理程序:

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

    我们将使用不同的方法将它附加到元素上,有些方法允许检查,有些方法不允许检查。

    方法a)单个事件处理程序

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

    方法b)多个事件处理程序

    1
    2
    3
    4
    5
    6
    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

    1
    $(element).click(handler);
    • 1.3、X

      1
      2
      3
      4
      5
      // inspect
      var clickEvents = $(element).data("events").click;
      jQuery.each(clickEvents, function(key, value) {
          alert(value) // alerts"function() { alert('clicked!') }"
      })
    • 1.4.x(将处理程序存储在对象内)

      1
      2
      3
      4
      5
      6
      // 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.datajQuery.data)

    方法D):原型(杂乱)

    1
    $(element).observe('click', handler);
    • 1.5、X

      1
      2
      3
      4
      5
      6
      // inspect
      Event.observers.each(function(item) {
          if(item[0] == element) {
              alert(item[2]) // alerts"function() { alert('clicked!') }"
          }
      })
    • 1.6至1.6.0.3,包括在内(这里非常困难)

      1
      2
      3
      4
      5
      6
      // 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(稍好一点)

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


    chrome、firefox、vivaldi和safari在其开发工具控制台中支持getEventListeners(domElement)

    对于大多数调试目的,可以使用这个。

    以下是使用它的很好参考:https://developers.google.com/chrome developer tools/docs/commandline api getEventListenersObject


    Chrome浏览器或Safari浏览器中的WebKit浏览器现在可以执行此操作。当您在元素窗格中选择某个DOM元素时,它将显示该元素的事件侦听器。


    可以用javascript列出所有事件监听器:这并不难;您只需黑客处理prototype的HTML元素方法(在添加监听器之前)。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    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属性,其中包含所有的侦听器。它甚至可以删除具有匿名函数的监听器。


    在Google Chrome中使用GetEventListeners:

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


    (重写此问题的答案,因为它与此处相关。)

    调试时,如果您只想查看事件,我建议您…

  • 视觉事件
  • chrome开发者工具的element s部分:选择一个元素并在右下角查找"事件监听器"(类似于firefox)
  • 如果要在代码中使用事件,并且在1.8版之前使用jquery,则可以使用:

    1
    $(selector).data("events")

    以获取活动。从1.8版开始,不再使用.data("events")(请参阅此错误通知单)。你可以使用:

    1
    $._data(element,"events")

    另一个示例:在控制台的某个链接上写入所有单击事件:

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

    (有关工作示例,请参阅http://jsfiddle.net/hmsqc/)

    不幸的是,除了调试之外,不建议使用$.u数据,因为它是一个内部jquery结构,在将来的版本中可能会发生更改。不幸的是,我知道没有其他简单的方法来访问这些事件。


    1:使用element.addeventlistener Prototype.observe(查看源代码)

    2:你可以重写Element.addEventListenerto Remember(方便听众采用EventListenerList是删除从dom3物业规格的建议)。本代码是运行在任何事件的连接:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    (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);
      };
    })();

    所有的事件::阅读

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

    不要忘了与消除对重写Element.removeEventListenerElement.eventListenerList从自定义事件。

    3:特殊保健需要在Element.onclick物业

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

    4:不要忘了Element.onclick内容属性:这是两个不同的东西:

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

    所以你需要把它,太。

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

    视觉事件的书签(中提到的最流行的答案只有在自定义处理程序:steals库缓存

    It turns out that there is no standard method provided by the W3C
    recommended DOM interface to find out what event listeners are
    attached to a particular element. While this may appear to be an
    oversight, there was a proposal to include a property called
    eventListenerList to the level 3 DOM specification, but was
    unfortunately been removed in later drafts. As such we are forced to
    looked at the individual Javascript libraries, which typically
    maintain a cache of attached events (so they can later be removed and
    perform other useful abstractions).

    As such, in order for Visual Event to show events, it must be able to
    parse the event information out of a Javascript library.

    overriding元(即可能是可疑的,因为有一些具体特点收藏类礼品可以是不带电的,但它在JS编码),使它的工作的支持和eventlistenerlist natively在Firefox和Opera浏览器(IE7中的工作,是不是)。


    你可以管理本地的礼品包装方法通过把这一事件侦听器在顶部你的

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
        (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);

    H / T"les2


    火狐开发工具现在不在这。事件是由clicking所示的"EV"按钮右上显示的每个元素,包括jQuery的DOM和事件。

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


    如果有firebug,可以使用console.dir(object or array)在任何javascript标量、数组或对象的控制台日志中打印一个漂亮的树。

    尝试:

    1
    console.dir(clickEvents);

    1
    console.dir(window);


    基于解决方案的全工作的简-样的答案表现得很getEventListeners()Turon从控制台:

    有一个小bug(与duplicates。它不是破多反正)。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    (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])-删除所有的事件侦听器名称设置,如果删除事件侦听器的那只


    Opera 12(不是最新的基于Chrome Webkit引擎的)Dragonfly已经有一段时间了,并且明显显示在DOM结构中。在我看来,它是一个优秀的调试器,也是我仍然使用基于Opera 12的版本的唯一原因(没有V13、V14版本,而基于V15的Webkit仍然缺少Dragonfly)

    enter image description here


    原型1.7.1方式

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    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];
    }

    有漂亮的jQuery事件存在的扩展:

    enter image description here(题目源码)


    我想是在2.1和jQuery的,与"$().click() -> $(element).data("events").click;"的方法,它是不是有效。

    我意识到,只有美元。_日期()函数的作品在我的案例:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
        $(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);
        }
    1
    2
    3
    4
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js">

    <body>
    </body>


    更改这些函数将允许您记录添加的侦听器:

    1
    2
    3
    4
    EventTarget.prototype.addEventListener
    EventTarget.prototype.attachEvent
    EventTarget.prototype.removeEventListener
    EventTarget.prototype.detachEvent

    与其他听众一起阅读

    1
    2
    console.log(someElement.onclick);
    console.log(someElement.getAttribute("onclick"));

    我最近正在处理事件,希望查看/控制页面中的所有事件。在研究了可能的解决方案之后,我决定采用自己的方式创建一个自定义系统来监视事件。所以,我做了三件事。

    首先,我需要一个容器来容纳页面中的所有事件监听器:这是theEventListeners对象。它有三种有用的方法:add()remove()get()

    接下来,我创建了一个EventListener对象来保存事件所需的信息,即:targettypecallbackoptionsuseCapturewantsUntrusted,并添加了一个方法remove()来删除侦听器。

    最后,我扩展了本地的addEventListener()removeEventListener()方法,使它们与我创建的对象(EventListenerEventListeners)一起工作。

    用途:

    1
    2
    3
    4
    5
    var bodyClickEvent = document.body.addEventListener("click", function () {
        console.log("body click");
    });

    // bodyClickEvent.remove();

    addEventListener()创建EventListener对象,将其添加到EventListeners并返回EventListener对象,以便以后删除。

    EventListeners.get()可用于查看页面中的侦听器。它接受EventTarget或字符串(事件类型)。

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

    演示

    假设我们想了解当前页面中的每个事件侦听器。我们可以这样做(假设您使用的是脚本管理器扩展,在本例中是篡改)。以下脚本执行此操作:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    // ==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

    代码可以在我的存储库中找到。我不想把它贴在这里,因为它很长。

    更新:这似乎不适用于jquery。当我检查EventListener时,我看到回调是

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

    我相信这属于jquery,而不是实际的回调。jquery将实际回调存储在EventTarget的属性中:

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

    enter image description here

    要删除事件侦听器,需要将实际回调传递给removeEventListener()方法。因此,为了使jquery能够正常工作,需要进一步修改。我以后可能会解决这个问题。