如何在debugging时或从JavaScript代码中findDOM节点上的事件侦听器?

我有一个页面,一些事件监听器被连接到input框和select框。 有没有办法找出哪些事件监听器正在观察一个特定的DOM节点和什么事件?

事件附加使用:

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

如果您只需要检查页面上正在发生的事情,则可以尝试Visual Event书签。

更新 : Visual Event 2可用;

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

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

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

对于大多数debugging目的,这可以使用。

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

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

可以用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}); }; 

现在每个锚元素( a )都将有一个包含其所有侦听器的lastListenerInfo属性。 它甚至可以用匿名函数删除监听器。

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

debugging时,如果你只是想看到事件,我build议或者…

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

如果你想在你的代码中使用这些事件,并且在1.8版之前使用jQuery,你可以使用:

 $(selector).data("events") 

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

 $._data(element, "events") 

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

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

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

不幸的是, 使用$ ._数据除了debugging以外不推荐使用,因为它是一个内部的jQuery结构,在以后的版本中可能会改变。 不幸的是我知道没有其他简单的方法来访问事件。

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 attribute someElement.setAttribute("onclick","otherHandler(event)"); // content attribute 

所以你也需要处理它:

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

Visual Event书签(在最受欢迎的答案中提到)仅窃取自定义库处理程序caching:

事实certificate,没有W3C推荐的DOM接口提供的标准方法来找出哪些事件监听器被附加到一个特定的元素。 虽然这可能看起来是一个疏忽,但有一个build议,即将一个名为eventListenerList的属性包含到3级DOM规范中,但不幸的是在后来的草稿中被删除。 因此,我们不得不查看各个Javascript库,这些库通常会保留附加事件的caching(以便稍后可以删除它们并执行其他有用的抽象)。

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

元素重写可能是有问题的(即因为有一些DOM特有的function,比如直播集合,它们不能用JS编码),但它本身支持eventListenerList支持,它可以在Chrome,Firefox和Opera中工作(在IE7中不起作用)。

你可以通过把这个放在你的<head>的顶部来包装本地的DOM方法来pipe理事件监听器:

 <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

在Google Chrome中使用getEventListeners:

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

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

尝试:

 console.dir(clickEvents); 

要么

 console.dir(window); 

Firefox开发者工具现在可以做到这一点。 通过单击每个元素的显示右侧的“ev”button(包括jQuery和DOM事件)来显示事件。

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

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

在这里输入图像描述

基于Jan Turon的答案的完全可行的解决scheme – 像控制台中的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]) – 返回事件侦听器的列表,如果设置了名称,则返回该事件的侦听器数组

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

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

我试图在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> 

有很好的jQuery Events扩展

在这里输入图像描述 (主题来源 )