侦听 JavaScript 中的所有事件

IT技术 javascript
2021-03-16 00:00:45

我试图弄清楚如何侦听 JavaScript 对象上的所有事件。

我知道我可以添加这样的单个事件

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

我想弄清楚是否有一个包罗万象的东西,我想做这样的事情:

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

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

function myFunction() {
  alert(/*event name*/);
}
// End pseudocode
6个回答

对@roman-bekkiev 的回答进行更现代的重写:

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

请注意,您可以进一步自定义要捕获的内容,例如:

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

@ryanpcmcquen 我的意思是,您应该Object.getPrototypeOf()在子 html 节点上使用多个以获取事件属性。
2021-04-15 00:00:45
请注意,由于箭头函数('=>'),这在 IE 上不起作用。如果您想在 IE 上使用 eventListener,请使用 Roman 的答案。
2021-05-07 00:00:45

获取标准元素的事件。

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

但正如@jeremywoertink 提到的,任何其他事件也是可能的。

窗口上的所有事件呢?
2021-04-16 00:00:45
@Olegzandr,窗口有什么问题?只需替换myObjwindow. 但是,请注意,使用此功能,您还将侦听一些不存在的事件,例如,如果存在全局变量,onetwothree则上面的代码将向 event 添加一个侦听器'etwothree'( ͡° ͜ʖ ͡°)
2021-04-18 00:00:45

我讨厌这个问题在没有原生或优雅的解决方案的情况下仍然存在。

更好的解决方案?

这允许您CustomEvent为任何EventTarget使用订阅单个target.addEventListener('*', ...)

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

当然,更原生或更优雅的方式是使用原生Proxyonapply作为目标的dispatchEvent方法,但对于这篇文章来说,这可能会传达更少的信息。

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

已知的问题

显然,这仅在通过EventTargetsdispatchEvent方法驱动事件调度时有效。也就是说,通过鼠标事件(例如)自然触发事件是行不通的。需要有一种方法来包装由自然事件触发器调用的内部方法。

话虽如此,如果您有办法解决这个问题,请在另一个答案中展示您的想法。

您可以使用执行通配符的EventEmitter2像你所说的那样做一个笼统的问题是有太多的事件,你可以创建自己的。您必须创建一个数组,具体包含您正在谈论的事件,对其进行迭代,然后单独绑定每个事件。

据我所知,这是可能的。


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

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

我所知道的发出事件的唯一另一种方式是 via 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);
};

🔥函数片段🔥

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