如何在JavaScript或调试中找到DOM节点上的事件侦听器?

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

事件附加使用:

  1. 原型的Event.observe
  2. DOMaddEventListener
  3. 作为元素属性element.onclick
794250 次浏览

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

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

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

方法A)单事件处理程序

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

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

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

方法C:jQuery

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

     // inspectvar clickEvents = $(element).data("events").click;jQuery.each(clickEvents, function(key, value) {console.log(value) // "function() { alert('clicked!') }"})
  • 1.4. x(将处理程序存储在对象中)

     // inspectvar clickEvents = $(element).data("events").click;jQuery.each(clickEvents, function(key, handlerObj) {console.log(handlerObj.handler) // "function() { alert('clicked!') }"// also available: handlerObj.type, handlerObj.namespace})
  • 1.7+(非常好)

    使用来自这一评论的知识。

     events = $._data(this, 'events');for (type in events) {events[type].forEach(function (event) {console.log(event['handler']);});}

(参见jQuery.fn.datajQuery.data

方法D):原型(凌乱)

$(element).observe('click', handler);

在控制台中单击结果输出(显示函数的文本)时,控制台将直接导航到相关JS文件中函数声明的行。

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

尝试:

console.dir(clickEvents);

console.dir(window);

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

更新视觉事件2可用。

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

可以列出所有事件侦听器在JavaScript中:这并不难;你只需要破解prototype的超文本标记语言元素的方法(之前添加侦听器)。

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属性,其中包含其所有侦听器。它甚至适用于删除具有匿名函数的侦听器。

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

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

  1. 视觉事件
  2. Chrome开发者工具的元素部分:选择一个元素并在右下角查找“事件监听器”(类似于Firefox)

如果您想在代码中使用事件,并且您使用的是jQuery版本1.8之前,您可以使用:

$(selector).data("events")

从1.8版开始,不再使用. data(“事件”)(见这bug票)。您可以使用:

$._data(element, "events")

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

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

(参见http://jsfiddle.net/HmsQC/的工作示例)

不幸的是,使用$._data不推荐除了调试之外,因为它是一个内部jQuery结构,并且可能在未来的版本中更改。不幸的是,我知道没有其他简单的方法来访问事件。

原型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];}

Chrome、Firefox、Vivaldi和Safari在其Developer Tools控制台中支持getEventListeners(domElement)

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

下面是使用它的一个很好的参考:
getEventListeners函数


来自Clifford Fajardo的高度投票提示来自评论:

getEventListeners($0)将获取您在Chrome开发工具中关注的元素的事件侦听器。

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

输入图片描述

GoogleChrome中使用getEventListeners:

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

1:Prototype.observe使用Element.addEventListener(参见的源代码

2:您可以覆盖Element.addEventListener以记住添加的侦听器(handy属性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内容属性:这是两件不同的事情:

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

所以你也需要处理它:

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

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

原来没有W3C提供的标准方法推荐的DOM接口以找出事件侦听器是什么附加到一个特定的元素。虽然这似乎是一个由于疏忽,有一项提议包括一项名为Event ListenerList到3级DOM规范,但被不幸的是,在后来的草案中被删除了。因此,我们被迫查看了各个Javascript库,这些库通常维护附加事件的缓存(以便以后可以删除它们并删除它们)执行其他有用的抽象)。

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

元素重写可能是有问题的(即,因为有一些DOM特定的功能,如live集合,不能在JS中编码),但它在本地提供了Event ListenerList支持,并且可以在Chrome,Firefox和Opera中工作(在IE7中不起作用)。

Firefox开发人员工具现在可以做到这一点。通过单击每个元素显示右侧的“ev”按钮显示事件,包括jQueryDOM事件。

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

我试图在jQuery 2.1中做到这一点,而使用“$().click() -> $(element).data("events").click;”方法它不起作用。

我意识到只有$._data()函数在我的情况下有效:

	$(document).ready(function(){
var node = $('body');		
// Bind 3 events to body clicknode.click(function(e) { alert('hello');  }).click(function(e) { alert('bye');  }).click(fun_1);
// Inspect the events of bodyvar 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>

基于作者:Jan Turon的完全工作解决方案-在控制台的行为类似于getEventListeners()

(有一个小bug与重复。它不会破坏。)

(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 listfor(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])-删除所有事件侦听器,如果设置了名称,则仅删除该事件的侦听器

您可以通过将其放在<head>的顶部来包装用于管理事件侦听器的本机DOM方法:

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

H/T@les2

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

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

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

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

用法:

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

Demo

假设我们想知道当前页面中的每个事件侦听器。我们可以做到这一点(假设您使用的是脚本管理器扩展,在这种情况下是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,它需要进一步修改。我可能会在将来修复它。

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

EventTarget.prototype.addEventListenerEventTarget.prototype.attachEventEventTarget.prototype.removeEventListenerEventTarget.prototype.detachEvent

和其他听众一起读

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

粘贴在控制台中,使所有eventListeners打印在其超文本标记语言元素旁边

Array.from(document.querySelectorAll("*")).forEach(element => {const events = getEventListeners(element)if (Object.keys(events).length !== 0) {console.log(element, events)}})

2022年更新:

Chrome Developer Tools中,在Elements panel中,有Event Listeners选项卡,您可以在其中看到元素的侦听器。

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

开发者工具