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

IT技术 javascript testing addeventlistener dom-events
2021-01-21 23:02:25

这是我的问题:是否有可能以某种方式检查动态附加事件侦听器的存在?或者如何检查 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 在这里如果单击“为 2 添加 onclick”,然后单击“[链接 2]”,则事件触发良好,但“测试链接 2”始终报告 false。有人可以帮忙吗?

6个回答

我做了这样的事情:

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

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

这与 @conrad10781 的添加似乎是最可靠和最简单的方法。如果由于某种原因元素被重新渲染并且事件侦听器断开连接,则该属性也将被重置。
2021-03-24 23:02:25
我可能会变得愚蠢(对此有 74 个赞成票)但我认为elementClicked.setAttribute('listener', 'true');应该在addEventListender函数之外添加它 - 否则它只会在事件被触发时添加,因此实际上不允许您检查事件侦听器是否可靠地附加.
2021-03-26 23:02:25
这是我过去使用的方法。我的建议是使用非常具体的语法结构。IE 而不是“侦听器”,使用事件本身。所以“数据-事件-点击”。这为您希望做多个事件的事件提供了一些灵活性,并使事情更具可读性。
2021-03-27 23:02:25
在发布时这是最高投票,但是(如上面的评论)逻辑有点偏离。更好的选择如下(stackoverflow.com/a/69189193/1265200
2021-03-30 23:02:25

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

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

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

然后,您可以onclick通过返回!!elem.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);
 }
}
在我的用例中,用户可能会使用不同的选项卡打开相同的页面。这仅适用于事件只会附加在一个选项卡中的一个位置的情况。布尔值无法真正与是否附加事件保持同步,因为我们只是猜测它不是在加载时
2021-03-23 23:02:25
这需要您更改附加事件的代码以跟踪它是否已附加(类似于此答案)。如果您不控制代码,它将无法工作。
2021-04-05 23:02:25

可能的重复:检查元素上是否有事件侦听器。没有 jQuery 请在那里找到我的答案。

基本上这里是 Chromium (Chrome) 浏览器的技巧:

getEventListeners(document.querySelector('your-element-selector'));
更准确地说,在这里:stackoverflow.com/a/41137585/1431728
2021-04-01 23:02:25

tl;dr:不,您不能以任何本机支持的方式执行此操作。


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

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

第 1 步:首先,您需要一个可以遍历存储对象并返回给定元素(或 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;
}

第 2 步:然后,您将需要一个可以添加事件侦听器但也可以将侦听器插入存储对象的函数。

/* 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;
}

第 4 步:最后,您将需要一个可以从存储对象中删除侦听器的函数。

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

片段:


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

感谢您提供此解决方案,它简单而坚固。一句话,有一个小错误。函数“removeListener”检查事件数组是否为空但三元不正确。它应该说“if (record.listeners[event].length!=-1)”。
2021-03-31 23:02:25