如何在 javascript 中为所有事件添加事件侦听器而不单独列出它们?

Posted

技术标签:

【中文标题】如何在 javascript 中为所有事件添加事件侦听器而不单独列出它们?【英文标题】:How can I add an event listener for all events in javascript without listing them individually? 【发布时间】:2017-02-19 04:54:03 【问题描述】:

我想使用通配符完成以下代码(我认为不存在?)

myObject.element = document.getElementsByClassName('js-myObject');
myObject.element.addEventListener('click', myObject.click);
myObject.element.addEventListener('mouseover', myObject.mouseover);
//etc..

到目前为止,我有以下内容

myObject.controller = function(e)
   if( (e.type in myObject) && (typeof myObject[e.type] ==='function') )
      myObject[e.type](e);
   
;

//but the listeners still have to be assigned as such
myObject.element = document.getElementsByClassName('js-myObject');
myObject.element.addEventListener('click', myObject.controller);
myObject.element.addEventListener('mouseover', myObject.controller);
//etc...


// but I want to do (and it doesn't work)
myObject.element.addEventListener('*', myObject.controller);

对于事件数组和 foreach 语句以外的方法有什么建议吗?

编辑,我目前的解决方案

我接受了下面的答案(没有可用的通配符,解析可能数百个事件是个坏主意)

对于那些寻找类似功能的人,我已经确定了以下方法,至少目前是这样。

for(var prop in myObject)
  if (!myObject.hasOwnProperty(prop)continue;
  if (typeof myObject[prop] !== 'function')continue;
  myObject.element.addEventListener(prop, myObject[prop]);

好处是我不必返回并为其添加侦听器的自定义事件的处理程序。缺点是我必须确保在定义每个 myObject.someEvent() 之后调用此函数。我在 myObject.init(); 中调用它这对我来说很好。请注意,此解决方案不符合我以前的规范,因为它使用 for/each 循环——但它完成了我真正想要完成的工作,非常感谢@torazaburo 明确定义了我的技术限制和缺乏智慧初步计划。

【问题讨论】:

把你的对象放在一个数组中,并在一个循环中设置处理程序 或使用 jquery,它会这样做 ***.com/questions/7439570/… @Pamblam 请理解我正在寻找一种方法来避免列出每个事件。 强烈怀疑您想为所有事件添加监听器。 ['click', 'mouseover'].forEach(evt => myObject.element.addEventListener(evt, myObject.controller)); 怎么了? 【参考方案1】:

没有通配符,但使用 jQuery,您可以拥有 1 个长事件侦听器行,而不是多个。

How do you log all events fired by an element in jQuery?

像这样:

('body').on("click mousedown mouseup focus blur keydown change dblclick mousemove mouseover mouseout mousewheel keydown keyup keypress textInput touchstart touchmove touchend touchcancel resize scroll zoom select change submit reset",function(e)
     console.log(e);
); 

【讨论】:

这是一个很好的资源——感谢 mmcrae,但仍然不是我想要的。即,它不处理自定义事件。我想知道javascript是否不允许我正在寻找的东西。 (另外,如果它不是一个完整的解决方案,我宁愿不需要 jquery) 不处理自定义事件是什么意思?然后只需将其添加到click mycustomevent mousedown的字符串中? 我无法编辑关于不处理自定义事件的评论。但是您必须手动添加每个自定义事件。同样,我正在寻找通配符类型的解决方案 似乎是一个奇怪的要求,将某些东西绑定到每一个可能的事件......但是 idk。无论如何,谷歌搜索 jquery wildcard event 会导致您可能应该查看的内容,例如 ***.com/questions/9735608/… 缺少输入,粘贴【参考方案2】:

聚会有点晚了,但这是我添加所有事件侦听器并将它们记录到控制台的方法:

Object.keys(window).forEach(key => 
    if(/./.test(key))
        window.addEventListener(key.slice(2), event => 
            console.log(key, event)
        )
    
)

【讨论】:

测试不应该是/^on/ 吗? (以“开”开头) @SamHasler 你是对的。已经有一段时间了,但我相信我在某个时候将它与事件发射器一起使用,所以我只是删除了那部分。 我刚刚注意到的一件有趣的事情:即使没有 /^on/,它似乎也不会为 GamePad 事件触发...【参考方案3】:

没有添加* 侦听器的功能,我怀疑您是否希望在一个元素上监听数百个事件。

顺便说一句,您应该使用涉及EventListener 接口和handleEvent 方法的被低估的方法,而不是以myObject.controller 的形式为通用事件处理程序创建自己的架构它定义了。

【讨论】:

@torazabura -- 谢谢。这被接受为答案,因为当其他人试图解决它时,他们不符合我的标准。 1. 没有 foreach,2. 所有事件 这在 chrome 中不起作用。我使用document.body.addEventListener('*', function(e) console.log('event', e); ); 尝试过它在 chrome 或 firefox 中不起作用。起作用的是个别事件。不起作用的是多个事件。 @MrMesees 如果您阅读了整个评论,您会注意到上面的代码实际上是 user663031 引用了 OP。 那么他们应该使用一种机制来显示,比如blockquote和cite【参考方案4】:

如何自己实现addEventListener('*')

对于所有本机事件,我们可以通过遍历 target.onevent 属性并为所有事件安装我们的侦听器来检索支持的事件列表。

for (const key in target) 
    if(/^on/.test(key)) 
        const eventType = key.substr(2);
        target.addEventListener(eventType, listener);
    

据我所知,发出事件的唯一另一种方式是通过EventTarget.dispatchEvent,每个Node 和因此每个Element 都继承。 要监听所有这些手动触发的事件,我们可以全局代理dispatchEvent 方法,并为我们刚刚看到的名称的事件安装我们的监听器✨ ^^

const dispatchEvent_original = EventTarget.prototype.dispatchEvent;
EventTarget.prototype.dispatchEvent = function (event) 
    if (!alreadyListenedEventTypes.has(event.type)) 
        target.addEventListener(event.type, listener, ...otherArguments);
        alreadyListenedEventTypes.add(event.type);
    
    dispatchEvent_original.apply(this, arguments);
;

? 函数 sn-p ?

function addEventListenerAll(target, listener, ...otherArguments) 

    // install listeners for all natively triggered events
    for (const key in target) 
        if (/^on/.test(key)) 
            const eventType = key.substr(2);
            target.addEventListener(eventType, listener, ...otherArguments);
        
    

    // dynamically install listeners for all manually triggered events, just-in-time before they're dispatched ;D
    const dispatchEvent_original = EventTarget.prototype.dispatchEvent;
    function dispatchEvent(event) 
        target.addEventListener(event.type, listener, ...otherArguments);  // multiple identical listeners are automatically discarded
        dispatchEvent_original.apply(this, arguments);
    
    EventTarget.prototype.dispatchEvent = dispatchEvent;
    if (EventTarget.prototype.dispatchEvent !== dispatchEvent) throw new Error(`Browser is smarter than you think!`);




// usage example
function addEventListenerAll(target, listener, ...otherArguments) 

    // install listeners for all natively triggered events
    for (const key in target) 
        if (/^on/.test(key)) 
            const eventType = key.substr(2);
            target.addEventListener(eventType, listener, ...otherArguments);
        
    

    // dynamically install listeners for all manually triggered events, just-in-time before they're dispatched ;D
    const dispatchEvent_original = EventTarget.prototype.dispatchEvent;
    function dispatchEvent(event) 
        target.addEventListener(event.type, listener, ...otherArguments);  // multiple identical listeners are automatically discarded
        dispatchEvent_original.apply(this, arguments);
    
    EventTarget.prototype.dispatchEvent = dispatchEvent;
    if (EventTarget.prototype.dispatchEvent !== dispatchEvent) throw new Error(`Browser is smarter than you think!`);




// usage example
addEventListenerAll(window, (evt) => 
    console.log(evt.type);
);
document.body.click();
document.body.dispatchEvent(new Event('omg!',  bubbles: true ));


// usage example with `useCapture`
// (also receives `bubbles: false` events, but in reverse order)
addEventListenerAll(
    window,
    (evt) =>  console.log(evt.type); ,
    true
);
document.body.dispatchEvent(new Event('omfggg!',  bubbles: false ));

【讨论】:

【参考方案5】:

如果这就是你要找的东西,我不是 100%,但我认为这就是你要找的东西。

document 是我们通常为我们的事件标记的不包含事件。它实际上是祖父母类。

document -> htmlDocument -> Document (where you could find the onclick* events)

如您所见,我们可以这样做。只需在事件开始时修剪 on

Object.keys(document.__proto__.__proto__).reduce((arr, event)=> 
  if(event.startsWith('on')) return [...arr, event.substr(2)];
  return arr;
, [])

这将返回类似:

["readystatechange", "pointerlockchange", "pointerlockerror", "beforecopy", "beforecut", "beforepaste", "freeze", "resume", "search", "securitypolicyviolation", "visibilitychange", "copy", "cut", "paste", "abort", "blur", "cancel", "canplay", "canplaythrough", "change", "click", "close", "contextmenu", "cuechange", "dblclick", "drag", "dragend", "dragenter", "dragleave", "dragover", "dragstart", "drop", "durationchange", "emptied", "ended", "error", "focus", "formdata", "input", "invalid", "keydown", "keypress", "keyup", "load", "loadeddata", "loadedmetadata", "loadstart", "mousedown", "mouseenter", "mouseleave", "mousemove", "mouseout", "mouseover", "mouseup", "mousewheel", "pause", "play", "playing", "progress", "ratechange", "reset", "resize", "scroll", "seeked", "seeking", "select", "stalled", "submit", "suspend", "timeupdate", "toggle", "volumechange", "waiting", "webkitanimationend", "webkitanimationiteration", "webkitanimationstart", "webkittransitionend", "wheel", "auxclick", "gotpointercapture", "lostpointercapture", "pointerdown", "pointermove", "pointerup", "pointercancel", "pointerover", "pointerout", "pointerenter", "pointerleave", "selectstart", "selectionchange", "animationend", "animationiteration", "animationstart", "transitionend", "fullscreenchange", "fullscreenerror", "webkitfullscreenchange", "webkitfullscreenerror", "pointerrawupdate"]

这只是我想出的快速方法,我相信更聪明的人会提供更好的答案。您可能还想查看https://developer.mozilla.org/en-US/docs/Web/Events,其中包含您可能需要的内容。

【讨论】:

不错的解决方案,虽然我更喜欢 filter-map 来减少:.filter((prop) => prop.startsWith('on')).map((prop) => prop.substr(2))【参考方案6】:

getElementsByClassName 已经返回一个数组(或者更具体地说,一个HTMLCollection),而不是单个元素。循环执行即可。

myObject.element = document.getElementsByClassName('js-myObject');
for(var i=0; i<myObject.element.length; i++)
    myObject.element[i].addEventListener('click', myObject.controller);
    myObject.element[i].addEventListener('mouseover', myObject.controller);

编辑...澄清后..循环和数组仍然有用

var e = ['click', 'hover', 'focus', 'mouseover', 'mouseout'];
myObject.element = document.getElementsByClassName('js-myObject');
for(var i=0; i<myObject.element.length; i++)
    for(var n=0; n<e.length; n++)
        myObject.element[i].addEventListener(e[n], myObject.controller);

【讨论】:

我相信你错过了我的问题的重点。这不是为多个对象添加相同的侦听器。它是将所有侦听器添加到单个对象而不列出每个事件侦听器 他说的是向一个元素添加许多事件,而不是向许多元素添加事件 @pamblam 感谢更新——但我确实在问题中指定了我不想要数组和 foreach 循环。例如,该解决方案不会处理自定义事件 如果您将自定义事件添加到循环中,它将考虑它们。不幸的是,我认为这是你最好的选择。【参考方案7】:

查找页面上的所有事件监听器

getEventListeners(document)

Reference

把它们列出得更好一点

for (const [key, value] of Object.entries(getEventListeners(document))) 
      console.log(`$key`) 

我会留给你来实际做一些事情,但是现在你至少可以看到页面上存在的所有内容,你可以打开 DevTools 并在这个页面上尝试一下,你自己看看它确实有效。

【讨论】:

复制粘贴到 DevTools 中的代码以查看此页面有您可以列出的侦听器【参考方案8】:

这样的?

        document.addEventListener('click', function (event) 

            if (event.target.closest('.scroll')) 
                // Do something...
            

            if (event.target.matches('[data-some-attribute]')) 
                // Do something else...
            

            if (event.target.matches('#my-form')) 
                // Do another t hing...
            

        , false)

【讨论】:

以上是关于如何在 javascript 中为所有事件添加事件侦听器而不单独列出它们?的主要内容,如果未能解决你的问题,请参考以下文章

点击事件后:如何通过 javascript 向 URL 添加内容?

试图在JavaScript / jQuery中添加一个on click事件

如何在 Expression Blend 中的单个事件处理程序中为按钮单击添加多个事件?

JavaScript事件简述

在 iOS 中为 MBCalendarKit 创建事件

Android:如何在 ListView 的列表项中为 Button 设置 onClick 事件