这是我的问题:是否可以以某种方式检查是否存在一个动态附加的事件侦听器?或者我怎么能在DOM中检查“onclick”(?)属性的状态?我已经在互联网上搜索了一个解决方案,就像Stack Overflow,但没有运气。这是我的html:
<a id="link1" onclick="linkclick(event)"> link 1 </a>
<a id="link2"> link 2 </a> <!-- without inline onclick handler -->
然后在Javascript中,我附加了一个动态创建的事件监听器到第二个链接:
document.getElementById('link2').addEventListener('click', linkclick, false);
代码运行良好,但我所有的尝试检测附加的侦听器失败:
// test for #link2 - dynamically created eventlistener
alert(elem.onclick); // null
alert(elem.hasAttribute('onclick')); // false
alert(elem.click); // function click(){[native code]} // btw, what's this?
jsFiddle在这里。
如果你点击“Add onclick for 2”,然后点击“[link 2]”,事件会正常启动,
但是“测试链接2”总是报告错误。
有人能帮帮我吗?
我只是写了一个脚本来让你实现这个。它为您提供了两个全局函数:hasEvent(Node elm, String事件)和getEvents(Node elm),您可以利用它们。注意,它修改了EventTarget原型方法add/RemoveEventListener,并且不适用于通过HTML标记或elm的javascript语法添加的事件。On_event =…
更多信息在GitHub
现场演示
脚本:
var hasEvent,getEvents;!function(){function b(a,b,c){c?a.dataset.events+=","+b:a.dataset.events=a.dataset.events.replace(new RegExp(b),"")}function c(a,c){var d=EventTarget.prototype[a+"EventListener"];return function(a,e,f,g,h){this.dataset.events||(this.dataset.events="");var i=hasEvent(this,a);return c&&i||!c&&!i?(h&&h(),!1):(d.call(this,a,e,f),b(this,a,c),g&&g(),!0)}}hasEvent=function(a,b){var c=a.dataset.events;return c?new RegExp(b).test(c):!1},getEvents=function(a){return a.dataset.events.replace(/(^,+)|(,+$)/g,"").split(",").filter(function(a){return""!==a})},EventTarget.prototype.addEventListener=c("add",!0),EventTarget.prototype.removeEventListener=c("remove",!1)}();
似乎没有跨浏览器的函数来搜索在给定元素下注册的事件。
但是,可以使用某些浏览器的开发工具查看元素的回调函数。当试图确定网页的功能或调试代码时,这可能很有用。
火狐
首先,在开发人员工具中的Inspector选项卡中查看元素。这可以做到:
在页面上右键单击要检查的网页项,并从菜单中选择“检查元素”。
在控制台中使用函数来选择元素,例如document。querySelector,然后单击元素旁边的图标在Inspector选项卡中查看它。
如果向元素注册了任何事件,您将在元素旁边看到一个包含单词Event的按钮。单击它将允许您查看已在元素中注册的事件。单击事件旁边的箭头,可以查看该事件的回调函数。
铬
首先,在开发人员工具中的Elements选项卡中查看元素。这可以做到:
在页面上右键单击要检查的网页上的项目,并从菜单中选择“检查”
在控制台中使用函数来选择元素,例如document。querySelector,右键单击元素,选择“在元素面板中显示”,在Inspector选项卡中查看它。
在窗口中显示包含网页元素的树的部分附近,应该有另一个带有标题为“事件监听器”的选项卡的部分。选择它以查看注册到元素的事件。要查看给定事件的代码,请单击事件右侧的链接。
在Chrome中,一个元素的事件也可以使用getEventListeners函数找到。但是,根据我的测试,当多个元素传递给getEventListeners函数时,它没有列出事件。如果你想在页面上找到所有有监听器的元素,并查看这些监听器的回调函数,你可以在控制台中使用以下代码来做到这一点:
var elems = document.querySelectorAll('*');
for (var i=0; i <= elems.length; i++) {
var listeners = getEventListeners(elems[i]);
if (Object.keys(listeners).length < 1) {
continue;
}
console.log(elems[i]);
for (var j in listeners) {
console.log('Event: '+j);
for (var k=0; k < listeners[j].length; k++) {
console.log(listeners[j][k].listener);
}
}
}
如果您知道在给定浏览器或其他浏览器中执行此操作的方法,请编辑此答案。
如果我理解得很好,你只能检查是否检查了一个听众,而不能检查哪个听众是具体的演示者。
因此,一些特别的代码将填补空白,以处理您的编码流。一种实用的方法是使用变量创建状态。例如,像下面这样附加一个监听器的检查器:
var listenerPresent=false
然后如果你设置了一个监听器,只需要改变这个值:
listenerPresent=true
然后在你的eventListener的回调中,你可以在里面分配特定的函数,以同样的方式,根据某些状态作为变量来分配对函数的访问:
accessFirstFunctionality=false
accessSecondFunctionality=true
accessThirdFunctionality=true
我写了一个Chrome扩展,需要确定页面上的哪些元素响应点击。我是这样做的:
(1)舱单。Json,设置“run_at”属性为“document_start”。(我们需要在页面开始运行之前注入一个脚本。)
(2)在你的内容脚本中,添加一段代码注入一个脚本到页面中,该脚本将覆盖EventTarget.prototype.addEventListener来标记所有动态分配点击监听器的元素:
let flagClickHandledElements = function() {
let oldEventListener = EventTarget.prototype.addEventListener;
EventTarget.prototype.addEventListener = function(event_name, handler_func) {
if (event_name === 'click') {
if (this.setAttribute) {
this.setAttribute('data-has_click_handler', true);
}
}
if (oldEventListener)
oldEventListener(event_name, handler_func);
}
}
function injectScript(func) {
let codeString = '(' + func + ')();';
let script = document.createElement('script');
script.textContent = codeString;
(document.head||document.documentElement).appendChild(script);
}
injectScript(flagClickHandledElements);
(3)将“webNavigation”添加到manifest.json中的“permissions”列表中
(4)在后台脚本中添加一些代码,当页面加载完成时通知内容脚本:
function onPageDoneLoading(details)
{
chrome.tabs.sendMessage(details.tabId, {"action": "doneloading"});
}
chrome.webNavigation.onCompleted.addListener(onPageDoneLoading);
(5)当页面加载完成时,让你的内容脚本注入另一个脚本到页面中,扫描页面上的所有元素,寻找老式的“onclick”处理程序:
let gatherOldStyleClickHandledElements = function() {
let all_elements = document.getElementsByTagName("*");
for (let i = 0; i < all_elements.length; i++) {
let el = all_elements[i];
if (el.setAttribute && el.onclick) {
el.setAttribute('data-has_click_handler', true);
}
}
}
function onReceiveMessage(request) {
if (request.action === 'doneloading') {
injectScript(gatherOldStyleClickHandledElements);
} else {
console.log('Unrecognized message');
}
return Promise.resolve("Dummy response to keep the console quiet");
}
(6)最后,你可以在你的内容脚本中测试一个元素,看看它是否有一个像这样的点击处理程序:
if (el.getAttribute('data-has_click_handler'))
console.log('yep, this element has a click handler');
2022年更新:
我在TypeScript中编写了实用工具方法,根据这个答案附加和分离事件,但这个答案是正确的。希望有人觉得有用。
export const attachEvent = (
element: Element,
eventName: string,
callback: () => void
) => {
if (element && eventName && element.getAttribute('listener') !== 'true') {
element.setAttribute('listener', 'true');
element.addEventListener(eventName, () => {
callback();
});
}
};
export const detachEvent = (
element: Element,
eventName: string,
callback: () => void
) => {
if (eventName && element) {
element.removeEventListener(eventName, callback);
}
};
导入并像这样在任何地方使用它
attachEvent(domElement, 'click', this.myfunction.bind(this));
detachEvent(domElement, 'click', this.myfunction);
你好,我在这里提出我的方法,它以某种方式工作,以避免在DOM的同一元素上进行多个侦听。我的方法使用JQUERY,但原理如下:
在对应用程序进行特定处理(必须在DOM元素(如click)上重新生成侦听器)之后,我们首先删除该事件以避免多次出现该事件,然后立即重新创建它。
这一原则要根据需要加以调整。这只是原理。我向你展示如何在jquery。
line 1 : $(_ELTDOM_).unbind('click');
line 2 : $(_ELTDOM_).bind('click',myFct);
我希望通过调整这个解决方案可以帮助到一些人。我坚持认为,这种解决方案不一定适用于所有情况,但它已经使解决与双、三重……相关的问题成为可能。例如,由于同一元素上的多个侦听而导致的同时处理
我写了3个函数来做这个:
var addEvent = function(object, type, callback)
{
if (object != null && typeof(object) != 'undefined' && object.addEventListener)
{
object.isAttached = typeof object.isAttached == "undefined" ? [] : object.isAttached;
if (!object.isAttached[type])
{
object.isAttached[type] = true;
object.addEventListener(type, callback, false);
}
}
};
var removeEvent = function(object, type, callback)
{
if (object != null && typeof(object) != "undefined" && typeof object.isAttached != "undefined" && object.isAttached[type])
{
object.removeEventListener(type, callback, false);
object.isAttached[type] = false;
}
};
var hasEvent = function(object, type, callback)
{
return object != null && typeof(object) != "undefined" && typeof object.isAttached != "undefined" && object.isAttached[type];
};
函数的使用很简单:
function mousemove(e)
{
console.log("x:" + e.clientX + ", y:" + e.clientY);
}
if (hasEvent(window, "mousemove", mousemove))
console.log('window has "mousemove" event with "mousemove" callback');
else
console.log('window does not have "mousemove" event with "mousemove" callback');
addEvent(window, "mousemove", mousemove);
if (hasEvent(window, "mousemove", mousemove))
console.log('window has "mousemove" event with "mousemove" callback');
else
console.log('window does not have "mousemove" event with "mousemove" callback');
/*
Output
window does not have "mousemove" event with "mousemove"
window has "mousemove" event with "mousemove" callback
The x and y coordinates of mouse as you move it
*/