【问题标题】:Listen for all events in JavaScript监听 JavaScript 中的所有事件
【发布时间】:2015-02-03 23:08:55
【问题描述】:

我正在尝试弄清楚如何侦听 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

【问题讨论】:

  • 你为什么要这样做?
  • 你有没有想过这个问题?是否可行?
  • @putvande 为什么不呢?不,实际上不可能通过一个函数调用开始监听所有事件。你需要知道这些名字。请参阅下面的答案。我认为 user3780616 试图找到一个在他执行不同操作时触发的事件。他正在尝试查找事件的名称。

标签: javascript


【解决方案1】:

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

【讨论】:

  • 请注意,由于箭头功能('=>'),这在 IE 上不起作用。如果您想在 IE 上使用 eventListener,请使用 Roman 的答案。
  • @ryanpcmcquen 我的意思是,您应该在子 html 节点上使用多个 Object.getPrototypeOf() 以获取事件属性。
【解决方案2】:

获取标准元素的事件。

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

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

【讨论】:

  • window 上的所有事件呢?
  • @Olegzandr,窗口有什么问题?只需将myObj 替换为window。但是,请注意,您会收听一些不存在的事件,例如如果有一个全局变量onetwothree,上面的代码将添加一个监听器到事件'etwothree'。 ( ͡° ͜ʖ ͡°)
【解决方案3】:

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

更好的解决方案?

这允许您使用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);

当然,一个更原生或者[也许]更优雅的方式是在apply 上使用原生Proxy 作为目标的dispatchEvent 方法,但是为了这篇文章的缘故,这可能会传达得更少。

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

已知问题

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

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

【讨论】:

    【解决方案4】:

    你可以使用EventEmitter2 来做通配符。像你所说的那样做一个包罗万象的问题是有这么多事件,你可以创建自己的。您必须专门制作一个数组,其中包含您正在谈论的事件,对其进行迭代,然后单独绑定每个事件。

    【讨论】:

      【解决方案5】:

      据我所知,这是可能的。


      对于所有本机事件,我们可以通过遍历 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
      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 }));
      

      【讨论】:

        【解决方案6】:

        您可能应该选择您想要收听的事件,将它们放入一个数组并迭代每个:

        ['click','mouseover'].forEach(function(ev) {
            el.addEventListener(ev, function() {
                console.log('event:', ev)
            })
        })
        

        【讨论】:

        • 现在好像坏了。我正在尝试追查谁更改了什么以及何时更改,但到目前为止还没有运气..
        • 是的,Event.prototype 已更改。无论如何,这是一种气味,我将其从答案中删除。
        • 正确,所以一个好的解决方案能够获取所有事件名称的列表,有没有办法检索所有可能的事件名称列表?
        • 这没有回答问题
        【解决方案7】:
        //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)
        
                }
            });
        

        【讨论】:

        • 如何监听文档上的所有事件?你添加一个click 监听器,就是这样
        • 错字,我是说所有点击事件。
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2016-12-06
        • 1970-01-01
        • 2020-06-21
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多