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

问题描述 投票:759回答:18

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

事件附件使用:

  1. Prototype's Event.observe;
  2. DOM的addEventListener;
  3. 作为元素属性element.onclick
javascript events dom
18个回答
491
投票

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

更新:Visual Event 2可用;


18
投票

Firefox开发人员工具现在就这样做了。通过单击每个元素显示右侧的“ev”按钮显示事件,包括<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> 事件。


12
投票

如果你有jQuery,你可以使用DOM在任何JavaScript标量,数组或对象的控制台日志中打印一个漂亮的树。

尝试:

Firebug

要么

console.dir(object or array)

8
投票

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


8
投票

基于console.dir(window); 的完全工作解决方案 - 表现得像来自控制台的Dragonfly

(有一个重复的小错误。无论如何它都没有破坏。)

answer by Jan Turon

用法:

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

(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]; }; })(); - 删除所有事件侦听器,如果设置了name,则只删除该事件的侦听器


4
投票

原型1.7.1方式

someElement.getEventListeners([name])

3
投票

有很好的someElement.clearEventListeners([name])

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 Events extension


2
投票

我试图在jQuery 2.1中这样做,并使用“enter image description here”方法它不起作用。

我意识到只有$ ._ data()函数适用于我的情况:

source
$().click() -> $(element).data("events").click;

1
投票

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

	$(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>

0
投票

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

首先,我需要一个容器用于页面中的所有事件监听器:这是theEventTarget.prototype.addEventListener EventTarget.prototype.attachEvent EventTarget.prototype.removeEventListener EventTarget.prototype.detachEvent 对象。它有三种有用的方法:console.log(someElement.onclick); console.log(someElement.getAttribute("onclick")); EventListenersadd()

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

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

用法:

EventListener

EventListeners创建了一个var bodyClickEvent = document.body.addEventListener("click", function () { console.log("body click"); }); // bodyClickEvent.remove(); 对象,将其添加到addEventListener()并返回EventListener对象,因此可以在以后删除它。

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

EventListeners.get()

演示

假设我们想知道当前页面中的每个事件监听器。我们可以这样做(假设你使用脚本管理器扩展,在这种情况下是Tampermonkey)。以下脚本执行此操作:

EventTarget

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

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

代码可以在我的// ==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); 找到我不想在这里发布,因为它相当长。


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

screenshot of console listing all event listeners in this page

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

repository.

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

要删除事件侦听器,需要将实际回调传递给$(document.body).click(function () { console.log("jquery click"); }); 方法。所以为了使这个工作与jQuery,它需要进一步修改。我可能会在将来解决这个问题。


353
投票

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

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.datajQuery.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!') }" })

263
投票

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

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

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


85
投票

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


67
投票

可以在JavaScript中列出所有事件监听器:这并不难;你只需要破解prototype的HTML元素方法(在添加监听器之前)。

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

现在每个锚元素(qazxsw poi)都会有一个包含所有侦听器的qazxsw poi属性。它甚至可以用于删除具有匿名功能的侦听器。


45
投票

在Google Chrome中使用getEventListeners:

a

41
投票

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

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

  1. getEventListeners(document.getElementByID('btnlogin')); getEventListeners($('#btnlogin'));
  2. Chrome开发者工具的Elements部分:选择一个元素并在右下方查找“Event Listeners”(类似于Firefox)

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

this question

得到事件。从版本1.8开始,使用.data(“events”)已停止使用(请参阅Visual Event)。您可以使用:

$(selector).data("events")

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

this bug ticket

(有关工作示例,请参阅$._data(element, "events")

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


25
投票

1:var $myLink = $('a.myClass'); console.log($._data($myLink[0], "events").click); 使用Element.addEventListener(参见http://jsfiddle.net/HmsQC/

2:您可以覆盖Prototype.observe以记住添加的侦听器(方便的属性the source code已从DOM3规范提案中删除)。在附加任何事件之前运行此代码:

Element.addEventListener

阅读所有活动:

EventListenerList

并且不要忘记覆盖(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()); }); 中删除事件。

3:Element.removeEventListener物业需要特别照顾:

Element.eventListenerList

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

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

所以你也需要处理它:

Element.onclick

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

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

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

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


21
投票

您可以通过将其放在someElement.onclick = someHandler; // IDL attribute someElement.setAttribute("onclick","otherHandler(event)"); // content attribute 的顶部来包装用于管理事件侦听器的本机DOM方法:

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

H / T @ les2

© www.soinside.com 2019 - 2024. All rights reserved.