简体   繁体   English

侦听 JavaScript 中的所有事件

[英]Listen for all events in JavaScript

I'm trying to figure out how to listen for all events on a JavaScript object.我试图弄清楚如何侦听 JavaScript 对象上的所有事件。

I know that I can add individual events with something like this我知道我可以添加这样的单个事件

element.addEventListener("click", myFunction);
element.addEventListener("mouseover", myFunction);
...

I'm trying to figure out if there is a catch-all, I'd like to do something like this:我想弄清楚是否有一个包罗万象的东西,我想做这样的事情:

// Begin pseudocode
var myObj = document.getElementById('someID');

myObj.addEventListener(/*catch all*/, myFunction);

function myFunction() {
  alert(/*event name*/);
}
// End pseudocode

A more modern rewrite of @roman-bekkiev's answer:对@roman-bekkiev 的回答进行更现代的重写:

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

Note that you can further customize what you want to catch, for example:请注意,您可以进一步自定义要捕获的内容,例如:

/^on(key|mouse)/.test(key)

To pick up standard element's events.获取标准元素的事件。

var myObj = document.getElementById('someID');
for(var key in myObj){
    if(key.search('on') === 0) {
       myObj.addEventListener(key.slice(2), myFunction)
    }
}

But as @jeremywoertink mentioned any other events are also possible.但正如@jeremywoertink 提到的,任何其他事件也是可能的。

I hate that this problem persists without a native or elegant solution.我讨厌这个问题在没有原生或优雅的解决方案的情况下仍然存在。

A Better Solution?更好的解决方案?

This allows you to subscribe to a single CustomEvent for any EventTarget using target.addEventListener('*', ...) .这允许您使用target.addEventListener('*', ...)为任何EventTarget订阅单个CustomEvent

    clear();

    /**
     * @param : source := EventTarget
     *  *   EventTarget.prototype
     *  *   Node (Element, Attr, etc)
     * @usage : [Node].addEventListener('*', ({ detail: e }) => {...}, false);
     */
    function proxyEventTargetSource(source) {
        var emit = source.dispatchEvent;  // obtain reference

        function proxy(event) {
            var { type } = event, any = new CustomEvent('*', { detail: event });  // use original event as detail
            if (!{ '*': true }[ type ]) emit.call(this, any);  // only emit "any" if type is not any.type ('*')
            return emit.call(this, event);
        }

        if ({ 'dispatchEvent': true }[ emit.name ]) source.dispatchEvent = proxy;  // attempt overwrite only if not already set (avoid rewrapping)
        return (source.dispatchEvent === proxy);  // indicate if its set after we try to
    }

    // proxyEventTargetSource(EventTarget.prototype);  // all targets
    proxyEventTargetSource(document);  // single target
    var e = new CustomEvent('any!', { detail: true });
    document.addEventListener('*', (e) => console.log('type: %s, original: %s, e: %O', e.type, e.detail.type, e), false);
    document.dispatchEvent(e);

Granted, a more native or [perhaps] more elegant way would be to use a native Proxy on apply for the target's dispatchEvent method, but that would maybe convey less for the sake of this post.当然,更原生或更优雅的方式是在apply目标的dispatchEvent方法时使用原生Proxy ,但为了这篇文章,这可能传达的更少。

Gist: https://gist.github.com/cScarlson/875a9fca7ab7084bb608fb66adff0463要点: https : //gist.github.com/cScarlson/875a9fca7ab7084bb608fb66adff0463

Known Issues已知的问题

Apparently, this only works while driving event-dispatching through EventTargets 's dispatchEvent method.显然,这只适用于通过EventTargetsdispatchEvent方法驱动事件dispatchEvent That is, naturally triggering events through mouse events (for instance) does not work.也就是说,通过鼠标事件(例如)自然触发事件是行不通的。 There would need to be a way to wrap the internal method being called by natural event-triggers.需要有一种方法来包装由自然事件触发器调用的内部方法。

That being said, if you have a way around this, please show what you have in another answer.话虽如此,如果您有办法解决这个问题,请在另一个答案中展示您的想法。

You could use EventEmitter2 which does wildcards.您可以使用EventEmitter2做通配符。 The problem with doing a catchall like you're talking about is that there are so many events, and you can create your own.像你所说的那样做一个包罗万象的问题是有很多事件,你可以创建自己的。 You'd have to make an array of specifically which events you're talking about, iterate over that, and bind each one individually.您必须制作一组您正在谈论的具体事件,迭代它,然后单独绑定每个事件。

As far as I know, it's possible.据我所知,这是可能的。


For all native events , we can retrieve a list of supported events by iterating over the target.onevent properties and installing our listener for all of them.对于所有原生事件,我们可以通过遍历target.onevent属性并为所有事件安装我们的侦听器来检索支持的事件列表。

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

The only other way that events are emitted which I know of is via EventTarget.dispatchEvent , which every Node and thefore every Element inherits.我所知道的唯一发出事件的其他方式是通过EventTarget.dispatchEvent ,每个Node和之前的每个Element继承它。
To listen for all these manually triggered events , we can proxy the dispatchEvent method globally and install our listener just-in-time for the event whose name we just saw ✨ ^^为了监听所有这些手动触发的事件,我们可以全局代理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);
};

🔥 function snippet 🔥 🔥函数片段🔥

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

You should probably pick the events you want to listen to, put them into an array and iterate over each:您可能应该选择要收听的事件,将它们放入一个数组中并遍历每个:

['click','mouseover'].forEach(function(ev) {
    el.addEventListener(ev, function() {
        console.log('event:', ev)
    })
})
//listening for all click events on the document
   document.addEventListener('click', function (event) {

    //filtering for only events that happen on elements that contain the class
    //view_btn.          
  if (event.target.classList.contains( 'view_btn' )){
//logging out the id of the element        
          var id_of_clicked_element = event.target.getAttribute("id"); //
          console.log("button clicked has is of " + id_of_clicked_element)

        }
    });

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM