¿Uso correcto de addEventListener () / attachEvent ()?

81

Me pregunto cómo usar addEventListenerrespectivamente attachEventcorrectamente.

window.onload = function (myFunc1) { /* do something */ }

function myFunc2() { /* do something */ }

if (window.addEventListener) {
  window.addEventListener('load', myFunc2, false);
} else if (window.attachEvent) {
  window.attachEvent('onload', myFunc2);
}

 // ...

o

function myFunc1() { /* do something */ }

if (window.addEventListener) {
  window.addEventListener('load', myFunc1, false);
} else if (window.attachEvent) {
  window.attachEvent('onload', myFunc1);
}

function myFunc2() { /* do something */ }

if (window.addEventListener) {
  window.addEventListener('load', myFunc2, false);
} else if (window.attachEvent) {
  window.attachEvent('onload', myFunc2);
}

 // ...

?

¿Es seguro para todos los navegadores o debería elegir algo como esto?

function myFunc1(){ /* do something */ }
function myFunc2(){ /* do something */ }
// ...

function addOnloadEvent(fnc){
  if ( typeof window.addEventListener != "undefined" )
    window.addEventListener( "load", fnc, false );
  else if ( typeof window.attachEvent != "undefined" ) {
    window.attachEvent( "onload", fnc );
  }
  else {
    if ( window.onload != null ) {
      var oldOnload = window.onload;
      window.onload = function ( e ) {
        oldOnload( e );
        window[fnc]();
      };
    }
    else
      window.onload = fnc;
  }
}

addOnloadEvent(myFunc1);
addOnloadEvent(myFunc2);
// ...

AND: Say myfunc2es solo para IE 7. ¿Cómo modificar el método correcto / preferido en consecuencia?

ginny
fuente
Puede que no le guste que le diga esto, pero ¿por qué no usaría un marco para tratar estos problemas?
Puntiagudo
Lo haría, pero no puedo en este caso. Entonces, ¿podrías ayudarme con esto, por favor?
ginny
@ginny Echa un vistazo a mi respuesta. Avísame si necesitas más explicaciones.
hitautodestruct
1
Como mínimo, no debería probar el modelo de evento cada vez que desee registrar un evento. Esto se puede separar fácilmente en una función común, a la que se le pasa el elemento , el tipo de evento y el controlador .
MrWhite

Respuestas:

132

El uso de ambos es similar, aunque ambos adoptan una sintaxis ligeramente diferente para el parámetro de evento:

addEventListener ( referencia mdn ):

Compatible con los principales navegadores (FF, Chrome, Edge)

obj.addEventListener('click', callback, false);

function callback(){ /* do stuff */ }

Lista de eventos para addEventListener.

attachEvent ( referencia de msdn ):

Compatible con IE 5-8 *

obj.attachEvent('onclick', callback);

function callback(){ /* do stuff */ }

Lista de eventos para attachEvent.

Argumentos

Para ambos métodos, los argumentos son los siguientes:

  1. Es el tipo de evento.
  2. Es la función a llamar una vez que se ha disparado el evento.
  3. ( addEventListenersolo) Si es verdadero, indica que el usuario desea iniciar la captura .

Explicación

Ambos métodos se utilizan para lograr el mismo objetivo de adjuntar un evento a un elemento.
La diferencia es que attachEventsolo se puede usar en motores de renderizado de tridentes más antiguos ( IE5 + IE5-8 *) y addEventListeneres un estándar W3 que se implementa en la mayoría de los demás navegadores (FF, Webkit, Opera, IE9 +).

Para un soporte sólido de eventos en varios navegadores, incluidas las normalizaciones que no obtendrá con la solución Diaz, use un marco .

* IE9-10 admite ambos métodos, para compatibilidad con versiones anteriores.

Gracias a Luke Puplett por señalar que attachEventse ha eliminado de IE11.

Implementación mínima entre navegadores

Como Smitty recomendó, debería echar un vistazo a este addEvent de Dustin Diaz para una implementación sólida en varios navegadores sin el uso de un marco:

function addEvent(obj, type, fn) {
  if (obj.addEventListener) {
    obj.addEventListener(type, fn, false);
  }
  else if (obj.attachEvent) {
    obj["e"+type+fn] = fn;
    obj[type+fn] = function() {obj["e"+type+fn](window.event);}
    obj.attachEvent("on"+type, obj[type+fn]);
  }
  else {
    obj["on"+type] = obj["e"+type+fn];
  }
}

addEvent( document, 'click', function (e) {
  console.log( 'document click' )
})

hitautodestruct
fuente
@CamiloMartin Siempre vale la pena dar una buena respuesta si luego recibe un comentario como este, gracias :)
hitautodestruct
13
addEventListenertambién es compatible con IE9 +.
MrWhite
1
attachEvent se ha eliminado en IE11, por lo que el código que detecta IE y usa esta API ahora fallará. Todavía no he visto que esto suceda, pero he notado que la suplantación de la cadena del agente IE10 desde IE11 puede causar errores de script.
Luke Puplett
@LukePuplett La implementación de dustin diaz se basa en la detección de funciones, no en la detección del navegador. ¿Es a eso a lo que te refieres?
hitautodestruct
7

Cualquiera que siga participando en esta discusión y no encuentre la respuesta que estaba buscando para pagar:
http://dustindiaz.com/rock-solid-addevent

Esta es una de las soluciones más elegantes que encontré para aquellos de nosotros con restricciones en el uso de los marcos.

function addEvent(obj, type, fn) {

    if (obj.addEventListener) {
        obj.addEventListener(type, fn, false);
        EventCache.add(obj, type, fn);
    } else if (obj.attachEvent) {
        obj["e" + type + fn] = fn;
        obj[type + fn] = function() {
            obj["e" + type + fn](window.event);
        }
        obj.attachEvent("on" + type, obj[type + fn]);
        EventCache.add(obj, type, fn);
    } else {
        obj["on" + type] = obj["e" + type + fn];
    }

}

var EventCache = function() {

    var listEvents = [];
    return {
        listEvents: listEvents,
        add: function(node, sEventName, fHandler) {
            listEvents.push(arguments);
        },
        flush: function() {
            var i, item;

            for (i = listEvents.length - 1; i >= 0; i = i - 1) {
                item = listEvents[i];
                if (item[0].removeEventListener) {
                    item[0].removeEventListener(item[1], item[2], item[3]);
                };

                if (item[1].substring(0, 2) != "on") {
                    item[1] = "on" + item[1];
                };

                if (item[0].detachEvent) {
                    item[0].detachEvent(item[1], item[2]);
                };

                item[0][item[1]] = null;
            };
        }
    };
}();

addEvent(window, 'unload', EventCache.flush);
Smitty
fuente