简体   繁体   中英

Capture all the events (javascript)

I want to be able to capture all events that are both created and dispatched and fire some callback when that happens.

Also, I would like to be able to fire a callback anytime an event is paired with an event listener.

Problems include: dynamically added elements, events whose propagation or bubbling is prevented, and custom events that are generated dynamically. I imagine there would need to be a prototyping of dispatchEvent or something, but I am unsure. Is this even possible?

Some event basics:

  1. Events are dispatched "on" a DOM object (usually an element) that is the event target.
  2. Events can firstly propagate down to child elements in a capture phase. This phase is rarely used since it wasn't supported by some widely used browsers until recently.
  3. Events can secondly propagate up to parent elements in a bubbling phase. This phase is commonly used.
  4. Some events don't propagate, they have neither a capture or bubble phase (eg focus, blur and submit events). Some events that propagate in some browsers don't propagate in others.
  5. DOM elements that respond to events have an event handler. It can be set to listen for particular events and call a listener function when that event reaches the element, either during capture, bubbling or if the element is an event target.
  6. Listeners can cancel propagation, eg a click event on a span inside a link can cancel propagation so the link doesn't get the click

Given the above, it is a practical impossibility to "capture all events" using the Events API . It would require establishing a listener for every event type on every element and be impossible to capture custom events because you have to know about them to set an appropriate listener.

I imagine there would need to be a prototyping of dispatchEvent or something

dispatchEvent is a method of an Event instance, it's not specified to be a constructor (there is no requirement for it to have an internal [[Construct]] method) so not practical to use as such. Browsers aren't required to implement prototype inheritance for host objects (though most do), and the implementation details of host objects and methods are largely hidden, so this is not an option.

You might try extending the Event API, but you really should not mess with host objects .

It seems that you are concerned about dynamically added elements. There is a strategy called " event delegation " , where you work out the events you need to listen for, then setup listeners as close to the event targets as you can on an element that doesn't change (eg a table element if you are dynamically adding and removing table rows, or a container div for other elements) for the specific event types you need to respond to.

You can also have the functions that are modifying the DOM dispatch custom events to add listeners or whatever.

If you really want to do this, then you can override addEventListener to keep track of events being registered and fired.

var myEventManager = (function() {
    var old = EventTarget.prototype.addEventListener,
        listeners = [],
        events = [];

    EventTarget.prototype.addEventListener = function(type, listener) {

        function new_listener(listener) {
            return function(e) {
                events.push(e);                  // remember event
                return listener.call(this, e);   // call original listener
            };
        }

        listeners.push([type, listener]);        // remember call
        return old.call(this, type, new_listener(listener));  // call original
    };

    return {
        get_events: function() { return events; },
        get_listeners: function() {return listeners; }
    };

}());

However, there are uncountable reasons not to do this, not least the fact that you will quickly run out of memory as you record thousands of events such as mouse moves. This will also not capture event listeners set in ways such as elt.onclick . Nor of course will it catch listeners set up via the old IE attachEvent API. Most importantly, it will not help with you that events that are generated and listened for internally, such as a mouse click on a check box. (A complete solution would also require handling removeEventListener .)

You can also override createEvent and dispatch in similar fashion, but again, that will capture only events that are explicitly created or dispatched in the JS code.

If you really want to do what you seem to be wanting to, I guess you need to fork Chrome.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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