这是我的问题:是否可以以某种方式检查是否存在一个动态附加的事件侦听器?或者我怎么能在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”总是报告错误。 有人能帮帮我吗?


当前回答

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

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

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

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

其他回答

我写了一个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');

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

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

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

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

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

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

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

下面是我用来检查是否存在动态附加事件侦听器的脚本。我使用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');
}

我要做的是在你的函数外面创建一个布尔值,开始时为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);
 }
}