2012-02-20 20 views
6

He creado una función de fábrica de emisor de eventos de fábrica multipropósito. Con él puedo convertir objetos en emisores de eventos. El código para la fábrica del emisor del evento está debajo si alguien desea echarle un vistazo o usarlo.Obtener una matriz de todos los eventos de DOM posibles

Mi pregunta es cómo puedo obtener una lista de eventos del DOM. Tenga en cuenta que no estoy tratando de obtener una lista de eventos combinados. Quiero una lista de todos los eventos posibles. Quiero agregar un método de "tubería" a los emisores. Este método tomaría un objeto DOM y se uniría a todos los posibles eventos, luego, cuando cualquiera de esos eventos disparara, se desencadenaría un evento con el mismo nombre en el emisor.

No creo que haya una forma de hacerlo. Estoy preparado para hacer una matriz codificada de nombres de eventos, pero si pudiera obtener la matriz para el DOM en su lugar sería mucho mejor y aún funcionaría si el W3C estandariza más tipos de eventos.

P.S. Si trabajas para el W3C, este es el tipo de basura que hace que todos odien el DOM. Por favor deja de tratar JavaScript como un lenguaje de juguete. No es un lenguaje de juguete y necesita más que tu juguete DOM.

/** 
* Creates a event emitter 
*/ 
function EventEmitter() { 
    var api, callbacks; 

    //vars 
    api = { 
     "on": on, 
     "trigger": trigger 
    }; 
    callbacks = {}; 

    //return the api 
    return api; 

    /** 
    * Binds functions to events 
    * @param event 
    * @param callback 
    */ 
    function on(event, callback) { 
     var api; 

     if(typeof event !== 'string') { throw new Error('Cannot bind to event emitter. The passed event is not a string.'); } 
     if(typeof callback !== 'function') { throw new Error('Cannot bind to event emitter. The passed callback is not a function.'); } 

     //return the api 
     api = { 
      "clear": clear 
     }; 

     //create the event namespace if it doesn't exist 
     if(!callbacks[event]) { callbacks[event] = []; } 

     //save the callback 
     callbacks[event].push(callback); 

     //return the api 
     return api; 

     function clear() { 
      var i; 
      if(callbacks[event]) { 
       i = callbacks[event].indexOf(callback); 
       callbacks[event].splice(i, 1); 

       if(callbacks[event].length < 1) { 
        delete callbacks[event]; 
       } 

       return true; 
      } 
      return false; 
     } 
    } 

    /** 
    * Triggers a given event and optionally passes its handlers all additional parameters 
    * @param event 
    */ 
    function trigger(event ) { 
     var args; 

     if(typeof event !== 'string' && !Array.isArray(event)) { throw new Error('Cannot bind to event emitter. The passed event is not a string or an array.'); } 

     //get the arguments 
     args = Array.prototype.slice.apply(arguments).splice(1); 

     //handle event arrays 
     if(Array.isArray(event)) { 

      //for each event in the event array self invoke passing the arguments array 
      event.forEach(function(event) { 

       //add the event name to the begining of the arguments array 
       args.unshift(event); 

       //trigger the event 
       trigger.apply(this, args); 

       //shift off the event name 
       args.shift(); 

      }); 

      return; 
     } 

     //if the event has callbacks then execute them 
     if(callbacks[event]) { 

      //fire the callbacks 
      callbacks[event].forEach(function(callback) { callback.apply(this, args); }); 
     } 
    } 
} 
+0

He hecho una pregunta similar: [¿Es posible atrapar programáticamente todos los eventos en la página en el navegador?] (Http://stackoverflow.com/questions/5107232/is-it-possible-to-programmatically -catch-all-events-en-la-página-en-el-navegador). –

Respuesta

5

Aquí hay una versión que funciona en Chrome, Safari y FF.

Object.getOwnPropertyNames(document).concat(Object.getOwnPropertyNames(Object.getPrototypeOf(Object.getPrototypeOf(document)))).filter(function(i){return !i.indexOf('on')&&(document[i]==null||typeof document[i]=='function');}) 

UPD:

Y aquí es la versión que funciona en IE9 +, Chrome, Safari y FF.

Object.getOwnPropertyNames(document).concat(Object.getOwnPropertyNames(Object.getPrototypeOf(Object.getPrototypeOf(document)))).concat(Object.getOwnPropertyNames(Object.getPrototypeOf(window))).filter(function(i){return !i.indexOf('on')&&(document[i]==null||typeof document[i]=='function');}).filter(function(elem, pos, self){return self.indexOf(elem) == pos;}) 

PD: el resultado es una serie de eventos de renombre como ["onwebkitpointerlockerror", "onwebkitpointerlockchange", "onwebkitfullscreenerror", "onwebkitfullscreenchange", "onselectionchange", "onselectstart", "onsearch", "onreset", "onpaste", "onbeforepaste", "oncopy"] ... ect.

5

Todos los eventos DOM comienzan con on. Puede recorrer cualquier instancia de Element y enumerar todas las propiedades que comienzan con on.

Ejemplo. Copiar y pegar el código siguiente en la consola (Firefox, usando comprensiones de matriz;)):

[i for(i in document)].filter(function(i){return i.substring(0,2)=='on'&&(document[i]==null||typeof document[i]=='function');}) 

Otro método para obtener los eventos es examinado the specification, que revela:

// event handler IDL attributes 
    [TreatNonCallableAsNull] attribute Function? onabort; 
    [TreatNonCallableAsNull] attribute Function? onblur; 
    [TreatNonCallableAsNull] attribute Function? oncanplay; 
    [TreatNonCallableAsNull] attribute Function? oncanplaythrough; 
    [TreatNonCallableAsNull] attribute Function? onchange; 
    [TreatNonCallableAsNull] attribute Function? onclick; 
    [TreatNonCallableAsNull] attribute Function? oncontextmenu; 
    [TreatNonCallableAsNull] attribute Function? oncuechange; 
    [TreatNonCallableAsNull] attribute Function? ondblclick; 
    [TreatNonCallableAsNull] attribute Function? ondrag; 
    [TreatNonCallableAsNull] attribute Function? ondragend; 
    [TreatNonCallableAsNull] attribute Function? ondragenter; 
    [TreatNonCallableAsNull] attribute Function? ondragleave; 
    [TreatNonCallableAsNull] attribute Function? ondragover; 
    [TreatNonCallableAsNull] attribute Function? ondragstart; 
    [TreatNonCallableAsNull] attribute Function? ondrop; 
    [TreatNonCallableAsNull] attribute Function? ondurationchange; 
    [TreatNonCallableAsNull] attribute Function? onemptied; 
    [TreatNonCallableAsNull] attribute Function? onended; 
    [TreatNonCallableAsNull] attribute Function? onerror; 
    [TreatNonCallableAsNull] attribute Function? onfocus; 
    [TreatNonCallableAsNull] attribute Function? oninput; 
    [TreatNonCallableAsNull] attribute Function? oninvalid; 
    [TreatNonCallableAsNull] attribute Function? onkeydown; 
    [TreatNonCallableAsNull] attribute Function? onkeypress; 
    [TreatNonCallableAsNull] attribute Function? onkeyup; 
    [TreatNonCallableAsNull] attribute Function? onload; 
    [TreatNonCallableAsNull] attribute Function? onloadeddata; 
    [TreatNonCallableAsNull] attribute Function? onloadedmetadata; 
    [TreatNonCallableAsNull] attribute Function? onloadstart; 
    [TreatNonCallableAsNull] attribute Function? onmousedown; 
    [TreatNonCallableAsNull] attribute Function? onmousemove; 
    [TreatNonCallableAsNull] attribute Function? onmouseout; 
    [TreatNonCallableAsNull] attribute Function? onmouseover; 
    [TreatNonCallableAsNull] attribute Function? onmouseup; 
    [TreatNonCallableAsNull] attribute Function? onmousewheel; 
    [TreatNonCallableAsNull] attribute Function? onpause; 
    [TreatNonCallableAsNull] attribute Function? onplay; 
    [TreatNonCallableAsNull] attribute Function? onplaying; 
    [TreatNonCallableAsNull] attribute Function? onprogress; 
    [TreatNonCallableAsNull] attribute Function? onratechange; 
    [TreatNonCallableAsNull] attribute Function? onreset; 
    [TreatNonCallableAsNull] attribute Function? onscroll; 
    [TreatNonCallableAsNull] attribute Function? onseeked; 
    [TreatNonCallableAsNull] attribute Function? onseeking; 
    [TreatNonCallableAsNull] attribute Function? onselect; 
    [TreatNonCallableAsNull] attribute Function? onshow; 
    [TreatNonCallableAsNull] attribute Function? onstalled; 
    [TreatNonCallableAsNull] attribute Function? onsubmit; 
    [TreatNonCallableAsNull] attribute Function? onsuspend; 
    [TreatNonCallableAsNull] attribute Function? ontimeupdate; 
    [TreatNonCallableAsNull] attribute Function? onvolumechange; 
    [TreatNonCallableAsNull] attribute Function? onwaiting; 

    // special event handler IDL attributes that only apply to Document objects 
    [TreatNonCallableAsNull,LenientThis] attribute Function? onreadystatechange; 
+0

Nota.La lista de eventos anterior ** no está completa **. Por ejemplo, el elemento [''] (http://dev.w3.org/html5/spec/Overview.html#the-body-element) también define un conjunto de eventos. Simplemente busque el atributo '[TreatNonCallableAsNull] ¿Función? on' en la especificación para encontrar todos los eventos (HTML5). –

+0

He intentado recorrer los eventos de nivel 0 de DOM ya y no aparecen en un bucle for in porque en * los métodos no son enumerables cuando se dejan como nulos. Tenga en cuenta que no estoy tratando de capturar enlaces existentes. Estoy tratando de obtener una lista dinámica de posibles enlaces. –

+0

@RobertHurst En navegadores compatibles (modernos), todos los eventos son enumerables. Cuando aún no están definidos, tienen que ser 'nulos', por definición. Como los eventos ** se conocen de antemano **, recomiendo crear una lista de eventos e implementarla. Eso es mucho más eficiente que recorrer las propiedades de muchos elementos y filtrar los nombres de las propiedades. –

0

I' he leído las especificaciones y he confirmado que esto no es posible actualmente. ¡Gracias W3C por no proporcionarnos el medio ambiente más básico!

Pude resolver el problema sin sacrificar nada. Como dije antes, el tubo transporta cualquier evento desde otro emisor (como un nodo DOM) al emisor actual. Sin embargo, no necesito hacer nada hasta que alguien intente escuchar un evento. Internamente, lo que hago es unirme a emisores canalizados a medida que las personas se unen al emisor actual.

Tengo released the library si tiene curiosidad por ver lo que hice. El código para la tubería está en el método pipe() y el método on().

Cuestiones relacionadas