如何检查动态附加的事件监听器是否存在?

这是我的问题:是否可以以某种方式检查是否存在一个动态附加的事件侦听器?或者如何检查“onclick”的状态;(?)属性在DOM?我已经在互联网上搜索了一个解决方案,就像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?
< p > jsFiddle在这里。 如果你点击“Add onclick for 2”;然后“;[链接2]”,事件很好, 但是“测试链接2”;总是报告错误。 有人能帮帮我吗?< / p >
293178 次浏览

没有办法检查动态附加的事件侦听器是否存在。

查看事件监听器是否被附加的唯一方法是像这样附加事件监听器:

elem.onclick = function () { console.log (1) }

然后,您可以通过返回!!elem.onclick(或类似的东西)来测试事件侦听器是否附加到onclick

我要做的是在你的函数外面创建一个布尔值,开始时为FALSE,当你附加事件时被设置为TRUE。在再次附加事件之前,这将作为某种标志。这里有一个关于这个想法的例子。

// initial load
var attached = false;


// this will only execute code once
doSomething = function()
{
if (!attached)
{
attached = true;
//code
}
}


//attach your function with change event
window.onload = function()
{
var txtbox = document.getElementById('textboxID');


if (window.addEventListener)
{
txtbox.addEventListener('change', doSomething, false);
}
else if(window.attachEvent)
{
txtbox.attachEvent('onchange', doSomething);
}
}

下面是我用来检查是否存在动态附加事件侦听器的脚本。我使用jQuery附加一个事件处理程序到一个元素,然后触发该事件(在本例中是'click'事件)。通过这种方式,我可以检索和捕获仅在附加事件处理程序时才存在的事件属性。

var eventHandlerType;


$('#contentDiv').on('click', clickEventHandler).triggerHandler('click');


function clickEventHandler(e) {
eventHandlerType = e.type;
}


if (eventHandlerType === 'click') {
console.log('EventHandler "click" has been applied');
}

我刚刚通过尝试查看我的事件是否附加....发现了这一点

如果你有:

item.onclick

它将返回"null"

但如果你这样做了:

item.hasOwnProperty('onclick')

那么它就是“真”

所以我认为当你使用“addEventListener”来添加事件处理程序时,访问它的唯一方法是通过“hasOwnProperty”。我希望我知道为什么或怎么做,但在研究之后,我还没有找到一个解释。

我只是写了一个脚本来让你实现这个。它给了你两个全局函数:hasEvent(Node elm, String event)getEvents(Node elm),你可以利用它们。注意,它修改了EventTarget原型方法add/RemoveEventListener,并且不适用于通过HTML标记或elm.on_event = ...的javascript语法添加的事件

更多信息在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)}();
例如,你可以使用Chrome检查器手动检查EventListener是否存在。 在元素选项卡中,你有传统的“样式”子选项卡和另一个相邻的“事件监听器”。 它将提供所有eventlistener及其链接元素的列表

我是这样做的:

const element = document.getElementById('div');


if (element.getAttribute('listener') !== 'true') {
element.addEventListener('click', function (e) {
const elementClicked = e.target;
elementClicked.setAttribute('listener', 'true');
console.log('event has been attached');
});
}

在附加侦听器时为元素创建一个特殊属性,然后检查它是否存在。

博士tl;:不,你不能以任何本地支持的方式这样做。


我知道实现这一点的唯一方法是创建一个自定义存储对象,在其中保存添加的侦听器的记录。大致如下:

/* Create a storage object. */
var CustomEventStorage = [];

首先,你需要一个函数,它可以遍历存储对象并返回给定元素(或false)的元素记录。

/* The function that finds a record in the storage by a given element. */
function findRecordByElement (element) {
/* Iterate over every entry in the storage object. */
for (var index = 0, length = CustomEventStorage.length; index < length; index++) {
/* Cache the record. */
var record = CustomEventStorage[index];


/* Check whether the given element exists. */
if (element == record.element) {
/* Return the record. */
return record;
}
}


/* Return false by default. */
return false;
}

然后,你需要一个函数,既可以添加事件监听器,又可以将监听器插入存储对象。

/* The function that adds an event listener, while storing it in the storage object. */
function insertListener (element, event, listener, options) {
/* Use the element given to retrieve the record. */
var record = findRecordByElement(element);


/* Check whether any record was found. */
if (record) {
/* Normalise the event of the listeners object, in case it doesn't exist. */
record.listeners[event] = record.listeners[event] || [];
}
else {
/* Create an object to insert into the storage object. */
record = {
element: element,
listeners: {}
};


/* Create an array for event in the record. */
record.listeners[event] = [];


/* Insert the record in the storage. */
CustomEventStorage.push(record);
}


/* Insert the listener to the event array. */
record.listeners[event].push(listener);


/* Add the event listener to the element. */
element.addEventListener(event, listener, options);
}

步骤3:关于你的问题的实际要求,你将需要以下函数来检查一个元素是否已经为指定的事件添加了事件监听器。

/* The function that checks whether an event listener is set for a given event. */
function listenerExists (element, event, listener) {
/* Use the element given to retrieve the record. */
var record = findRecordByElement(element);


/* Check whether a record was found & if an event array exists for the given event. */
if (record && event in record.listeners) {
/* Return whether the given listener exists. */
return !!~record.listeners[event].indexOf(listener);
}


/* Return false by default. */
return false;
}

最后,你需要一个可以从存储对象中删除监听器的函数。

/* The function that removes a listener from a given element & its storage record. */
function removeListener (element, event, listener, options) {
/* Use the element given to retrieve the record. */
var record = findRecordByElement(element);


/* Check whether any record was found and, if found, whether the event exists. */
if (record && event in record.listeners) {
/* Cache the index of the listener inside the event array. */
var index = record.listeners[event].indexOf(listener);


/* Check whether listener is not -1. */
if (~index) {
/* Delete the listener from the event array. */
record.listeners[event].splice(index, 1);
}


/* Check whether the event array is empty or not. */
if (!record.listeners[event].length) {
/* Delete the event array. */
delete record.listeners[event];
}
}


/* Add the event listener to the element. */
element.removeEventListener(event, listener, options);
}

代码片段:

window.onload = function () {
var
/* Cache the test element. */
element = document.getElementById("test"),


/* Create an event listener. */
listener = function (e) {
console.log(e.type + "triggered!");
};


/* Insert the listener to the element. */
insertListener(element, "mouseover", listener);


/* Log whether the listener exists. */
console.log(listenerExists(element, "mouseover", listener));


/* Remove the listener from the element. */
removeListener(element, "mouseover", listener);


/* Log whether the listener exists. */
console.log(listenerExists(element, "mouseover", listener));
};
<!-- Include the Custom Event Storage file -->
<script src = "https://cdn.rawgit.com/angelpolitis/custom-event-storage/master/main.js"></script>


<!-- A Test HTML element -->
<div id = "test" style = "background:#000; height:50px; width: 50px"></div>


虽然自OP发布这个问题以来已经过去了5年多,但我相信将来偶然发现这个问题的人会从这个答案中受益,所以请随意提出建议或改进。😊

理论上,你可以通过addEventListener和removeEventListener来为“this”对象添加remove标志。丑八怪和我还没测试过…

可能重复:检查元素上是否有事件监听器。没有jQuery

下面是Chrome浏览器的基本技巧:

getEventListeners(document.querySelector('your-element-selector'));

似乎没有跨浏览器的函数来搜索在给定元素下注册的事件。

但是,可以使用某些浏览器的开发工具查看元素的回调函数。当试图确定网页的功能或调试代码时,这可能很有用。

火狐

首先,查看开发人员工具中的检查员选项卡中的元素。这可以做到:

  • 在页面上通过右键单击你想检查的网页上的项目,并从菜单中选择“检查元素”。
  • 通过使用函数选择元素在控制台内,例如document.querySelector,然后单击元素旁边的图标,在检查员选项卡中查看它。

如果任何事件被注册到元素,你会在元素旁边看到一个包含单词事件的按钮。单击它将允许您查看已在元素中注册的事件。单击事件旁边的箭头,可以查看该事件的回调函数。

首先,查看开发人员工具中的元素选项卡中的元素。这可以做到:

  • 在页面上通过右键单击你想检查的网页上的项目,并从菜单中选择“检查”
  • 在控制台内通过使用函数来选择元素,例如document.querySelector,右键单击元素,并选择“在元素面板中显示”,在检查员选项卡中查看它。

在窗口中显示包含网页元素的树的部分附近,应该有另一个带有标题为“事件监听器”的选项卡的部分。选择它以查看注册到元素的事件。要查看给定事件的代码,请单击事件右侧的链接。

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

如果您知道在给定浏览器或其他浏览器中执行此操作的方法,请编辑此答案。

如果我理解得很好,你只能检查是否检查了一个听众,而不能检查哪个听众是具体的演示者。

因此,一些特别的代码将填补空白,以处理您的编码流。一个实用的方法是使用变量创建state。例如,像下面这样附加一个监听器的检查器:

var listenerPresent=false

然后如果你设置了一个监听器,只需要改变这个值:

listenerPresent=true

然后在你的eventListener的回调中,你可以在里面分配特定的函数,以同样的方式,根据某些状态作为变量来分配对函数的访问:

accessFirstFunctionality=false
accessSecondFunctionality=true
accessThirdFunctionality=true

只需删除事件,然后添加它:

document.getElementById('link2').removeEventListener('click', linkclick, false);
document.getElementById('link2').addEventListener('click', linkclick, false);

这种方法不存在,这似乎很奇怪。是时候加入了吗?

如果你想,你可以这样做:

var _addEventListener = EventTarget.prototype.addEventListener;
var _removeEventListener = EventTarget.prototype.removeEventListener;
EventTarget.prototype.events = {};
EventTarget.prototype.addEventListener = function(name, listener, etc) {
var events = EventTarget.prototype.events;
if (events[name] == null) {
events[name] = [];
}


if (events[name].indexOf(listener) == -1) {
events[name].push(listener);
}


_addEventListener(name, listener);
};
EventTarget.prototype.removeEventListener = function(name, listener) {
var events = EventTarget.prototype.events;


if (events[name] != null && events[name].indexOf(listener) != -1) {
events[name].splice(events[name].indexOf(listener), 1);
}


_removeEventListener(name, listener);
};
EventTarget.prototype.hasEventListener = function(name) {
var events = EventTarget.prototype.events;
if (events[name] == null) {
return false;
}


return events[name].length;
};

我通常附加一个类到元素,然后检查类是否存在,像这样:

let element = document.getElementsById("someElement");


if(!element.classList.contains('attached-listener'))
element.addEventListener("click", this.itemClicked);


element.classList.add('attached-listener');

像这样的东西应该有助于文档:

var listeners = window.getEventListeners(document);
Object.keys(listeners).forEach(event => {
console.log(event, listeners[event]);
});

或者使用选择器:

getAllEventListeners = function(el) {
var allListeners = {}, listeners;


while(el) {
listeners = getEventListeners(el);


for(event in listeners) {
allListeners[event] = allListeners[event] || [];
allListeners[event].push({listener: listeners[event], element: el});
}


el = el.parentNode;
}


return allListeners;
}

我写了一个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”;只要你“允许”;List在manifest.json中

(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');
var listenerPaste = pasteAreaElm.hasOwnProperty('listenerPaste');
if (!listenerPaste) {
pasteAreaElm.addEventListener("paste", onPasteEvent, false);
pasteAreaElm.listenerPaste = true;
}

//在匿名函数的外部赋值

const element = document.getElementById('div');
if (element && !element.hasAttribute('listenerOnClick')) {
element.addEventListener('click', function () {
const elementClicked = this;
// fnDoAnything(this); // maybe call a function with the elementClicked...
console.log('event has been attached');
});
}
element.setAttribute('listenerOnClick', 'true');

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

可以在JavaScript中列出所有事件监听器。您只需破解HTML元素的原型方法(在添加侦听器之前)。

此解决方案仅适用于谷歌Chrome或基于Chrome的浏览器

  1. 右键单击元素,选择“inspect”打开Chrome开发工具。
  2. 一旦开发工具打开,切换到“事件监听器”选项卡,您将看到所有事件监听器绑定到元素。

enter image description here

你好,我在这里提出我的方法,它以某种方式工作,以避免在DOM的同一元素上进行多个侦听。我的方法使用JQUERY,但原理如下:

在对应用程序进行特定处理(必须在DOM元素(如click)上重新生成侦听器)之后,我们首先删除该事件以避免多次出现该事件,然后立即重新创建它。

这一原则要根据需要加以调整。这只是原理。我向你展示如何在jquery。

line 1 : $(_ELTDOM_).unbind('click');
line 2 : $(_ELTDOM_).bind('click',myFct);

我希望通过调整这个解决方案可以帮助到一些人。我坚持认为,这种解决方案不一定适用于所有情况,但它已经使解决与双、三重……相关的问题成为可能。例如,由于同一元素上的多个侦听而导致的同时处理