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

Nav*_*eet 805 javascript events dom

我有一个页面,其中一些事件监听器附加到输入框和选择框.有没有办法找出哪些事件监听器正在观察特定的DOM节点以及哪些事件?

事件附件使用:

  1. 原型的 Event.observe ;
  2. DOM的addEventListener;
  3. 作为元素属性element.onclick.

And*_*ges 501

如果您只需要检查页面上发生的情况,可以尝试使用Visual Event书签.

更新:视觉事件2可用;

  • 这为页面添加了许多元素,其中许多是图像.在具有许多事件处理程序的页面上,它的实用性大大降低(我的17k和Visual Event需要大约3分钟才能加载). (21认同)
  • 我相信@ssharma提到的Chrome扩展程序是[这里提供的](https://chrome.google.com/webstore/detail/visual-event/pbmmieigblcbldgdokdjpioljjninaim) (15认同)
  • Chrome 和 FF 内部开发者工具 (F12) 具有内置事件查看器!Chrome:在“元素”选项卡上,选择元素并查看右侧有:样式、计算、_事件监听器_ (8认同)
  • 完美的!击败 Firebug 的“EventBug”插件。 (2认同)

Cre*_*esh 356

这取决于事件的附加方式.为了说明,我们有以下点击处理程序:

var handler = function() { alert('clicked!') };
Run Code Online (Sandbox Code Playgroud)

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

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

element.onclick = handler;
// inspect
alert(element.onclick); // alerts "function() { alert('clicked!') }"
Run Code Online (Sandbox Code Playgroud)

方法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
Run Code Online (Sandbox Code Playgroud)

方法C):jQuery

$(element).click(handler);
Run Code Online (Sandbox Code Playgroud)
  • 1.3.x的

    // inspect
    var clickEvents = $(element).data("events").click;
    jQuery.each(clickEvents, function(key, value) {
        alert(value) // alerts "function() { alert('clicked!') }"
    })
    
    Run Code Online (Sandbox Code Playgroud)
  • 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
    })
    
    Run Code Online (Sandbox Code Playgroud)

(见jQuery.fn.datajQuery.data)

方法D):原型(凌乱)

$(element).observe('click', handler);
Run Code Online (Sandbox Code Playgroud)
  • 1.5.x的

    // inspect
    Event.observers.each(function(item) {
        if(item[0] == element) {
            alert(item[2]) // alerts "function() { alert('clicked!') }"
        }
    })
    
    Run Code Online (Sandbox Code Playgroud)
  • 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!') }"
    })
    
    Run Code Online (Sandbox Code Playgroud)
  • 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!') }"
    })
    
    Run Code Online (Sandbox Code Playgroud)

  • @tomdemuyt在jQuery中,事件现在存储在内部数据数组中,而不是像以前一样通过`.data('events')访问.要访问内部事件数据,请使用`$ ._ data(elem,'events')`.请注意,此函数在jQuery源代码中标记为"仅供内部使用",因此没有承诺它将来会一直有效,但我相信它自jQuery 1.7以来一直有效并且仍然有效. (12认同)
  • @Jan,这似乎不适用于jQuery 1.7.2,该版本有不同的方法吗? (6认同)
  • 在"方法B"(addEventListener)上,这里是关于使用纯DOM Events API注册的处理程序的枚举工具状态的答案:http://stackoverflow.com/questions/7810534/have-any-browsers-implemented-the-dom3 -eventlistenerlist/7814692#7814692 (4认同)
  • Thx用于更新此内容.不幸的是,你必须通过每种类型的处理程序进行迭代. (3认同)

Rag*_*hav 299

Chrome,Firefox,Vivaldi和Safari getEventListeners(domElement)在其开发人员工具控制台中提供支持.

对于大多数调试目的,可以使用它.

以下是使用它的非常好的参考:https: //developers.google.com/chrome-developer-tools/docs/commandline-api#geteventlistenersobject

  • 提示:`getEventListeners($ 0)`将获取您在Chrome开发工具中关注的元素的事件监听器.我经常用这个.不必使用querySelector或get__By_函数 (38认同)
  • 不幸的是,虽然 Firebug 支持 `getEventListeners()`,但 Firefox 开发工具不支持它。([错误 1164285](https://bugzilla.mozilla.org/1164285)) (14认同)
  • 如果你已经解释了如何获取eventlistener的源代码,你可以节省我3个小时.那个"参考"没有解释任何事情.万一其他人在这里失败了如何:`var list = getEventListeners(document.getElementById("YOURIDHERE")); 的console.log(列表[ "焦点"] [0] [ "侦听器"].的toString())`.将"焦点"更改为要检查的事件,如果同一事件上有多个侦听器,则更改数字. (10认同)
  • 很好,但只能在Chrome控制台的命令行中运行:( (9认同)
  • @Raghav啊谢谢,用法是**`getEventListeners(object)`****NOT:**`obj getEventListeners()`正如我首先想到的那样:) (5认同)
  • +1。特定于浏览器的代码对我来说不是问题,因为我试图让我无法控制的页面正常工作。 (2认同)

Ish*_*han 85

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

  • 我不确定它是否显示*all*事件处理程序; 只是单个HTML事件处理程序. (9认同)
  • 我应该为Firebug提供EventBug插件以获得完整性<http://www.softwareishard.com/blog/category/eventbug/> (3认同)

Iva*_*nos 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});
};
Run Code Online (Sandbox Code Playgroud)

现在每个anchor元素(a)都有一个lastListenerInfo包含所有侦听器的属性.它甚至可以用于删除具有匿名功能的侦听器.

  • 难道你不能只修改`Node.prototype`吗?这就是`HTMLAnchorElement`无论如何继承`.addEventListener`的地方. (8认同)
  • 如果您正在编写用户脚本或内容脚本,则此方法将不起作用.这些天不仅可能是沙盒,而且你如何保证执行顺序? (4认同)
  • 您假设用户代理实现DOM主机对象的原型继承,并允许您修改它们.这些都不是好主意:[不要修改你不拥有的对象](http://www.nczonline.net/blog/2010/03/02/maintainable-javascript-dont-modify-objects-you-下自己/). (3认同)

Pra*_*oni 51

Google Chrome中使用getEventListeners :

getEventListeners(document.getElementByID('btnlogin'));
getEventListeners($('#btnlogin'));
Run Code Online (Sandbox Code Playgroud)

  • getEventListeners仅适用于Chrome的devtools控制台.这是这个更详细的答案的重复:http://stackoverflow.com/a/16544813/1026 (3认同)
  • 未捕获的 ReferenceError: getEventListeners 未定义 (2认同)

Luk*_*uke 41

(重写这个问题的答案,因为它在这里是相关的.)

调试时,如果你只是想看事件,我建议......

  1. 视觉事件
  2. Chrome开发者工具的Elements部分:选择一个元素并在右下方查找"Event Listeners"(类似于Firefox)

如果要在代码中使用事件,并且在1.8版之前使用jQuery ,则可以使用:

$(selector).data("events")
Run Code Online (Sandbox Code Playgroud)

得到事件.从版本1.8开始,使用.data("events")已停止使用(请参阅此错误凭单).您可以使用:

$._data(element, "events")
Run Code Online (Sandbox Code Playgroud)

另一个例子:将特定链接上的所有点击事件写入控制台:

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

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

不幸的是,使用$ ._ data不建议除了调试之外,因为它是一个内部jQuery结构,并且可能在将来的版本中发生变化.不幸的是,我知道没有其他简单的方法可以访问这些事件.

  • 我不是肯定的,但我认为`$ ._ data`的第一个参数可能需要是一个元素,而不是一个jQuery对象.所以我需要修改上面的例子``console.log($ ._ data($ myLink [0],"events").click);` (3认同)

Jan*_*roň 26

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);
  };
})();
Run Code Online (Sandbox Code Playgroud)

阅读所有活动:

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

并且不要忘记覆盖Element.removeEventListener以从自定义中删除事件Element.eventListenerList.

3:Element.onclick酒店需要特别照顾:

if(someElement.onclick)
  alert("I also listen tho this: "+someElement.onclick.toString());
Run Code Online (Sandbox Code Playgroud)

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

someElement.onclick = someHandler; // IDL attribute
someElement.setAttribute("onclick","otherHandler(event)"); // content attribute
Run Code Online (Sandbox Code Playgroud)

所以你也需要处理它:

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

Visual Event bookmarklet(在最流行的答案中提到)只窃取自定义库处理程序缓存:

事实证明,W3C推荐的DOM接口没有提供标准方法来找出哪些事件监听器附加到特定元素.虽然这似乎是一种疏忽,但有人建议将一个名为eventListenerList的属性包含在3级DOM规范中,但遗憾的是在后续草稿中删除了该属性.因此,我们不得不查看各个Javascript库,这些库通常维护附加事件的缓存(以便以后可以删除它们并执行其他有用的抽象).

因此,为了使Visual Event显示事件,它必须能够从Javascript库中解析事件信息.

元素重写可能有问题(即因为有一些DOM特定的功能,如实时集合,无法在JS中编码),但它本身提供了eventListenerList支持,它可以在Chrome,Firefox和Opera中运行(在IE7中不起作用) ).


Jon*_*n z 22

您可以将本地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>
Run Code Online (Sandbox Code Playgroud)

H/T @ les2


sim*_*ack 18

Firefox开发人员工具现在就这样做了.通过单击每个元素显示右侧的"ev"按钮显示事件,包括jQueryDOM事件.

检查器选项卡中Firefox开发人员工具的事件侦听器按钮的屏幕截图


alj*_*gom 14

2022 年更新:

在 中Chrome Developer ToolsElements panel有一个Event Listeners选项卡,您可以在其中查看该元素的侦听器。

您还可以取消选择“祖先”,以便它仅显示该元素的侦听器

开发者工具


Gab*_*son 13

获取页面上的所有 eventListeners 与其元素一起打印

Array.from(document.querySelectorAll("*")).forEach(e => {
    const ev = getEventListeners(e)
    if (Object.keys(ev).length !== 0) console.log(e, ev)
})
Run Code Online (Sandbox Code Playgroud)

  • 如果我尝试在 JS 文件中使用 `getEventListeners`,我会收到 Uncaught ReferenceError: getEventListeners is not Defined。 (3认同)

Mic*_*ler 12

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

尝试:

console.dir(clickEvents);
Run Code Online (Sandbox Code Playgroud)

要么

console.dir(window);
Run Code Online (Sandbox Code Playgroud)

  • 萤火虫1.12中的新功能https://getfirebug.com/wiki/index.php/GetEventListeners (9认同)

n00*_*00b 9

完全工作的解决方案基于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];
  };
})();
Run Code Online (Sandbox Code Playgroud)

用法:

someElement.getEventListeners([name]) - 返回事件侦听器列表,如果设置了name,则返回该事件的侦听器数组

someElement.clearEventListeners([name]) - 删除所有事件侦听器,如果设置了name,则仅删除该事件的侦听器

  • 这是一个很好的答案,但我不能让它在`body`和`document`元素上工作. (3认同)
  • @David Bradshaw:因为正文、文档和窗口有自己的原型,而不是元素原型...... (2认同)

Dan*_*ski 8

Opera 12(不是最新的Chrome Webkit引擎)Dragonfly已经有一段时间了,显然在DOM结构中显示.在我看来,它是一个优秀的调试器,是我仍然使用基于Opera 12的版本的唯一原因(没有v13,v14版本和基于v15 Webkit仍然缺乏Dragonfly)

在此输入图像描述


小智 5

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];
}
Run Code Online (Sandbox Code Playgroud)


Joe*_*rba 5

我试图在 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);
	}
Run Code Online (Sandbox Code Playgroud)
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>

<body>
</body>
Run Code Online (Sandbox Code Playgroud)


aki*_*uri 5

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

首先,我需要一个用于页面中所有事件侦听器的容器:这就是对象EventListeners。它具有三个有用的方法:add()remove()get()

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

最后,我扩展了本机addEventListener()removeEventListener()方法,使它们可以与我创建的对象(EventListenerEventListeners)一起使用。

用法:

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

// bodyClickEvent.remove();
Run Code Online (Sandbox Code Playgroud)

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

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

// EventListeners.get(document.body);
// EventListeners.get("click");
Run Code Online (Sandbox Code Playgroud)

演示

假设我们想了解当前页面中的每个事件侦听器。我们可以做到这一点(假设您使用脚本管理器扩展,在本例中为 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/event/event-listeners/event-listeners.js")
        .then(function (response) {
            return response.text();
        })
        .then(function (text) {
            eval(text);
            window.EventListeners = EventListeners;
        });
})(window);
Run Code Online (Sandbox Code Playgroud)

当我们列出所有侦听器时,它显示有 299 个事件侦听器。“似乎”有一些重复项,但我不知道它们是否真的重复。并非每个事件类型都是重复的,因此所有这些“重复项”可能是单个侦听器。

控制台的屏幕截图,列出了该页面中的所有事件侦听器

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


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

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

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

$(document.body).click(function () {
    console.log("jquery click");
});
Run Code Online (Sandbox Code Playgroud)

在此输入图像描述

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