提问人:Navneet 提问时间:1/15/2009 最后编辑:BBaysingerNavneet 更新时间:10/3/2023 访问量:904018
如何在JavaScript或调试中在DOM节点上查找事件侦听器?
How to find event listeners on a DOM node in JavaScript or in debugging?
问:
我有一个页面,其中一些事件侦听器附加到输入框和选择框。有没有办法找出哪些事件侦听器正在观察特定的 DOM 节点以及针对什么事件?
使用以下方法附加事件:
- 原型的
Event.observe
; - DOM的
addEventListener
; - 作为元素属性。
element.onclick
答:
这取决于事件的附加方式。为了说明这一点,假设我们有以下点击处理程序:
var handler = function() { alert('clicked!') };
我们将使用不同的方法将其附加到我们的元素上,有些方法允许检查,有些方法不允许。
方法 A) 单个事件处理程序
element.onclick = handler;
// inspect
console.log(element.onclick); // "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) { console.log(value) // "function() { alert('clicked!') }" })
1.4.x(将处理程序存储在对象中)
// inspect var 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.data 和 jQuery.data
)
方法D):原型(凌乱)
$(element).observe('click', handler);
1.5.x
// inspect Event.observers.each(function(item) { if(item[0] == element) { console.log(item[2]) // "function() { alert('clicked!') }" } })
1.6 到 1.6.0.3,包括 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){ console.log(wrapper.handler) // "function() { alert('clicked!') }" })
1.6.1(稍微好一点)
// inspect var clickEvents = element.getStorage().get('prototype_event_registry').get('click'); clickEvents.each(function(wrapper){ console.log(wrapper.handler) // "function() { alert('clicked!') }" })
在控制台中单击生成的输出(显示函数的文本)时,控制台将直接导航到相关 JS 文件中函数声明的行。
评论
addEventListener
.data('events')
$._data(elem, 'events')
如果你有 Firebug,你可以用来在任何 JavaScript 标量、数组或对象的控制台日志中打印一个漂亮的树。console.dir(object or array)
尝试:
console.dir(clickEvents);
或
console.dir(window);
评论
如果您只需要检查页面上发生的情况,则可以尝试使用视觉事件书签。
更新:Visual Event 2 可用。
评论
EventBug
Chrome 或 Safari 浏览器中的 WebKit Inspector 现在可以执行此操作。当您在“元素”窗格中选择 DOM 元素时,它将显示该元素的事件侦听器。
评论
可以在 JavaScript 中列出所有事件侦听器: 这并不难;您只需要破解 HTML 元素的方法(在添加侦听器之前)。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
评论
Node.prototype
HTMLAnchorElement
.addEventListener
removeEventListener
addEventListener
(重写这个问题的答案,因为它与此处相关。
调试时,如果您只想查看事件,我建议您...
- 视觉事件
- Chrome 开发者工具的 Elements 部分:选择一个元素并在右下角查找“Event Listeners”(类似于 Firefox)
如果要在代码中使用事件,并且使用的是 1.8 版之前的 jQuery,则可以使用:
$(selector).data("events")
以获取事件。从 1.8 版开始,不再使用 .data(“events”) (请参阅此错误票证)。您可以使用:
$._data(element, "events")
另一个例子:将所有点击事件写入控制台的某个链接上:
var $myLink = $('a.myClass');
console.log($._data($myLink[0], "events").click);
(有关工作示例,请参见 http://jsfiddle.net/HmsQC/)
不幸的是,除了调试之外,不建议使用 $._data,因为它是内部 jQuery 结构,并且可能会在将来的版本中更改。不幸的是,我不知道有其他简单的方法来访问这些事件。
评论
$._data(elem, "events")
似乎不适用于 jQuery 1.10,至少对于使用 .有谁知道如何调试这些?$(elem).on('event', ...)
$._data
console.log($._data($myLink[0], "events").click);
原型 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、Vivaldi 和 Safari 在其开发者工具控制台中提供支持。getEventListeners(domElement)
对于大多数调试目的,可以使用此功能。
下面是一个很好的使用它的参考:
getEventListeners 函数
克利福德·法哈多(Clifford Fajardo)在评论中高度投票的提示:
getEventListeners($0)
将获取您在 Chrome 开发工具中关注的元素的事件侦听器。
评论
getEventListeners(object)
NOT:正如我最初认为的那样:)obj getEventListeners()
var list = getEventListeners(document.getElementById("YOURIDHERE")); console.log(list["focus"][0]["listener"].toString())
getEventListeners($0)
Opera 12(不是最新的基于 Chrome Webkit 引擎)Dragonfly 已经有一段时间了,并且显然显示在 DOM 结构中。在我看来,它是一个出色的调试器,也是我仍然使用基于 Opera 12 的版本的唯一原因(没有 v13、v14 版本,基于 v15 Webkit 仍然缺少 Dragonfly)
在 Google Chrome 中使用 getEventListeners:
getEventListeners(document.getElementByID('btnlogin'));
getEventListeners($('#btnlogin'));
评论
1:使用 Element.addEventListener(参见源码Prototype.observe
)
2:您可以覆盖以记住添加的侦听器(方便的属性已从 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());
});
并且不要忘记覆盖以从自定义中删除事件。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 书签(在最流行的答案中提到)仅窃取自定义库处理程序缓存:
事实证明,W3C 没有提供标准方法 推荐 DOM 接口,找出事件监听器是什么 附加到特定元素。虽然这似乎是一个 监督,有一个提议包括一个名为 eventListenerList 设置为 3 级 DOM 规范,但 不幸的是,在后来的草案中被删除了。因此,我们被迫 查看了各个 Javascript 库,这些库通常 维护附加事件的缓存(以便以后可以删除它们,并且 执行其他有用的抽象)。
因此,为了让 Visual Event 显示事件,它必须能够 解析 Javascript 库中的事件信息。
元素覆盖可能是有问题的(即因为有一些特定于 DOM 的功能,如实时集合,不能用 JS 编码),但它原生提供了 eventListenerList 支持,并且适用于 Chrome、Firefox 和 Opera(在 IE7 中不起作用)。
Firefox 开发者工具现在可以做到这一点。通过单击每个元素显示右侧的“ev”按钮来显示事件,包括 jQuery 和 DOM 事件。
评论
我正在尝试在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>
评论
基于 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];
};
})();
用法:
someElement.getEventListeners([name])
- 返回事件侦听器列表,如果设置了 name,则返回该事件的侦听器数组
someElement.clearEventListeners([name])
- 删除所有事件侦听器,如果设置了 name only 删除该事件的侦听器
评论
body
document
你可以包装用于管理事件侦听器的原生 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>
H/T @les2
评论
存在不错的jQuery事件扩展:
(主题来源)
我最近在处理事件,并希望查看/控制页面中的所有事件。在研究了可能的解决方案后,我决定走自己的路,创建一个自定义系统来监控事件。所以,我做了三件事。
首先,我需要一个容器来容纳页面中的所有事件侦听器:这就是对象。它有三种有用的方法:、 和 。EventListeners
add()
remove()
get()
接下来,我创建了一个对象来保存事件的必要信息,即:、、、、、,并添加了一个删除侦听器的方法。EventListener
target
type
callback
options
useCapture
wantsUntrusted
remove()
最后,我扩展了原生 和 方法,使它们与我创建的对象 ( 和 ) 一起使用。addEventListener()
removeEventListener()
EventListener
EventListeners
用法:
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");
演示
假设我们想知道当前页面中的每个事件侦听器。我们可以做到这一点(假设您使用的是脚本管理器扩展,在本例中为 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);
当我们列出所有侦听器时,它说有 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");
});
若要删除事件侦听器,需要将实际回调传递给该方法。因此,为了使它与jQuery一起工作,它需要进一步修改。我将来可能会解决这个问题。removeEventListener()
更改这些函数将允许您记录添加的侦听器:
EventTarget.prototype.addEventListener
EventTarget.prototype.attachEvent
EventTarget.prototype.removeEventListener
EventTarget.prototype.detachEvent
读取其余侦听器
console.log(someElement.onclick);
console.log(someElement.getAttribute("onclick"));
粘贴到控制台中以将所有内容打印在其 HTML 元素旁边eventListeners
Array.from(document.querySelectorAll("*")).forEach(element => {
const events = getEventListeners(element)
if (Object.keys(events).length !== 0) {
console.log(element, events)
}
})
评论
getEventListeners
2022年更新:
在 中,有一个选项卡,您可以在其中查看元素的侦听器。Chrome Developer Tools
Elements panel
Event Listeners
您也可以取消选择“祖先”,以便它仅显示该元素的侦听器
目前,2023 年 9 月,在 Firefox 浏览器 117.0.1 中,您可以通过单击“开发者工具”中“检查器”中的相应“事件”按钮来查看此内容,如下所示:
要快速列出和/或删除文档或任何元素上的所有事件处理程序:
(仅适用于 Chrome 控制台,因为它使用 ,请参阅:
https://developer.chrome.com/docs/devtools/console/utilities/#getEventListeners-functiongetEventListeners()
)
let list = [];
let targets = Array.from(document.querySelectorAll('*'));
targets.push(document);
targets.forEach((obj) => {
let listeners = getEventListeners(obj);
for (p in listeners) {
listeners[p].forEach((l) => {
removeEventListener(l.type, l.listener, l.useCapture);
list.push([obj, l.type, l.listener, '' + l.listener, l.useCapture]);
});
}
});
console.table(list);
或键入控制台(或代码):
debugger;
单步执行代码以查找例如将鼠标悬停在元素上时究竟发生了什么。
debugger;
也非常适合停止停止任何失控的循环。
稍微相关,以停止大多数循环(hacky,但有效):
for (i = 0; i < 10000; i++) {
clearTimeout(i);
clearInterval(i);
cancelAnimationFrame(i);
}
评论
element.addEventListener(type, callback, [bubble])
element.onclick = function
Array.from(document.querySelectorAll("*")).forEach(e => { const ev = getEventListeners(e); if (Object.keys(ev).length !== 0) {console.log(e, ev)} })
addEventListener