Pregunta addEventListener vs onclick


Cuál es la diferencia entre addEventListener y onclick?

var h = document.getElementById("a");
h.onclick = dothing1;
h.addEventListener("click", dothing2);

El código anterior reside junto en un archivo .js separado, y ambos funcionan perfectamente.


508
2018-06-14 18:49


origen


Respuestas:


Ambos son correctos, pero ninguno de ellos es "lo mejor" per se, y puede haber una razón por la que el desarrollador eligió usar ambos enfoques.

Escuchadores de eventos (addEventListener y attachEvent de IE)

Las versiones anteriores de Internet Explorer implementan Javascript de forma diferente a prácticamente cualquier otro navegador. Con versiones de menos de 9, usa el attachEvent[doc] método, como este:

element.attachEvent('onclick', function() { /* do stuff here*/ });

En la mayoría de los otros navegadores (incluido IE 9 y superior), usted usa addEventListener[doc], Me gusta esto:

element.addEventListener('click', function() { /* do stuff here*/ }, false);

Usando este enfoque (DOM Nivel 2 eventos), puede adjuntar un número teóricamente ilimitado de eventos a cualquier elemento individual. La única limitación práctica es la memoria del lado del cliente y otras preocupaciones de rendimiento, que son diferentes para cada navegador.

Los ejemplos anteriores representan el uso de una función anónima [doc] También puede agregar un detector de eventos usando una referencia de función [doc] o un cierre [doc]

var myFunctionReference = function() { /* do stuff here*/ }

element.attachEvent('onclick', myFunctionReference);
element.addEventListener('click', myFunctionReference , false);

Otra característica importante de addEventListener es el parámetro final, que controla cómo el oyente reacciona a los eventos de burbujeo [doc] He estado pasando falso en los ejemplos, que es estándar para probablemente el 95% de los casos de uso. No hay un argumento equivalente para attachEvent, o cuando se usan eventos en línea.

Eventos en línea (HTML onclick = "" propiedad y element.onclick)

En todos los navegadores compatibles con JavaScript, puede poner un detector de eventos en línea, es decir, directamente en el código HTML. Probablemente has visto esto:

<a id="testing" href="#" onclick="alert('did stuff inline');">Click me</a>

Los desarrolladores más experimentados evitan este método, pero lo hacen bien; es simple y directo. No puede usar cierres o funciones anónimas aquí (aunque el controlador en sí es una función anónima) y su control de alcance es limitado.

El otro método que mencionas:

element.onclick = function () { /*do stuff here */ };

... es el equivalente de javascript en línea, excepto que tiene más control del alcance (ya que está escribiendo un script en lugar de HTML) y puede usar funciones anónimas, referencias a funciones y / o cierres.

La desventaja significativa con los eventos en línea es que, a diferencia de los oyentes de eventos descritos anteriormente, es posible que solo tenga asignado un evento en línea. Los eventos en línea se almacenan como un atributo / propiedad del elemento [doc], lo que significa que puede sobrescribirse.

Usando el ejemplo <a> del HTML de arriba:

var element = document.getElementById('testing');
element.onclick = function () { alert('did stuff #1'); };
element.onclick = function () { alert('did stuff #2'); };

... cuando hiciste clic en el elemento, hubieras solamente vea "Did stuff # 2" - sobrescribió el primero asignado del onclick propiedad con el segundo valor, y sobrescribió el HTML en línea original onclick propiedad también. Compruébalo aquí: http://jsfiddle.net/jpgah/.

¿Cuál es el mejor?

La pregunta es una cuestión de compatibilidad y necesidad del navegador. ¿Actualmente necesita adjuntar más de un evento a un elemento? ¿Lo harás en el futuro? Las probabilidades son, lo harás. attachEvent y addEventListener son necesarios. Si no, un evento en línea hará el truco.

jQuery y otros marcos de JavaScript encapsulan las diferentes implementaciones del navegador de los eventos de nivel 2 DOM en modelos genéricos para que pueda escribir código compatible con varios navegadores sin tener que preocuparse por la historia de IE como rebelde. Mismo código con jQuery, todo en navegador cruzado y listo para el rock:

$(element).on('click', function () { /* do stuff */ });

Sin embargo, no te quedes sin un marco para esta única cosa. Puede transferir fácilmente su propia pequeña utilidad para ocuparse de los navegadores más antiguos:

function addEvent(element, evnt, funct){
  if (element.attachEvent)
   return element.attachEvent('on'+evnt, funct);
  else
   return element.addEventListener(evnt, funct, false);
}

// example
addEvent(
    document.getElementById('myElement'),
    'click',
    function () { alert('hi!'); }
);

Intentalo: http://jsfiddle.net/bmArj/

Teniendo todo esto en cuenta, a menos que el guión que está viendo tome en cuenta las diferencias del navegador de otra manera (en el código no se muestra en su pregunta), la parte que utiliza addEventListener no funcionaría en versiones de IE menos de 9.

Documentación y lectura relacionada


728
2018-06-14 18:59



La diferencia que podría ver si tuviera otras dos funciones:

var h = document.getElementById('a');
h.onclick = doThing_1;
h.onclick = doThing_2;

h.addEventListener('click', doThing_3);
h.addEventListener('click', doThing_4);

Las funciones 2, 3 y 4 funcionan, pero 1 no. Esto es porque addEventListener no sobrescribe los controladores de eventos existentes, mientras que onclick anula cualquier existente onclick = fn manejadores de eventos.

La otra diferencia significativa, por supuesto, es que onclick siempre funcionará, mientras que addEventListener no funciona en Internet Explorer antes de la versión 9. Puede usar el análogo attachEvent (que tiene ligeramente sintaxis diferente) en IE <9.


128
2018-06-14 18:52



En esta respuesta, describiré los tres métodos para definir manejadores de eventos DOM.

element.addEventListener()

Ejemplo de código:

const element = document.querySelector('a');
element.addEventListener('click', event => event.preventDefault(), true);
<a href="//google.com">Try clicking this link.</a>

element.addEventListener() tiene múltiples ventajas:

  • Le permite registrarse ilimitado controladores de eventos y eliminarlos con element.removeEventListener().
  • Tiene useCapture parámetro, que indica si desea manejar el evento en su fase de captura o burbujeo. Ver: No se puede comprender el atributo useCapture en addEventListener.
  • Se preocupa por semántica. Básicamente, hace que el registro de controladores de eventos sea más explícito. Para un principiante, una llamada a función hace que sea obvio que algo pasa, mientras que asignar evento a alguna propiedad del elemento DOM es al menos no intuitivo.
  • Te permite estructura de documento separada (HTML) y lógica (JavaScript). En pequeñas aplicaciones web, puede parecer que no importa, pero hace importa con cualquier proyecto más grande. Es mucho más fácil mantener un proyecto que separa la estructura y la lógica que un proyecto que no lo hace.
  • Elimina la confusión con nombres de eventos correctos. Debido al uso de escuchas de eventos en línea o la asignación de oyentes de eventos a .onevent propiedades de los elementos DOM, muchos programadores de JavaScript inexpertos piensan que el nombre del evento es, por ejemplo, onclick o onload. on es no una parte del nombre del evento. Los nombres correctos de los eventos son click y load, y así es como los nombres de eventos se pasan a .addEventListener().
  • Trabaja en casi todos los navegadores. Si aún tiene que admitir IE <= 8, puede usar un polyfill de MDN.

element.onevent = function() {} (p.ej. onclick, onload)

Ejemplo de código:

const element = document.querySelector('a');
element.onclick = event => event.preventDefault();
<a href="//google.com">Try clicking this link.</a>

Esta era una forma de registrar manejadores de eventos en DOM 0. Ahora está desaconsejado, porque:

  • Le permite registrarse solo uno controlador de eventos. También eliminar el controlador asignado no es intuitivo, porque para eliminar el controlador de eventos asignado con este método, debe revertir onevent la propiedad vuelve a su estado inicial (es decir null)
  • No responder a los errores adecuadamente. Por ejemplo, si por error asigna una cadena a window.onload, por ejemplo: window.onload = "test";, no arrojará ningún error. Su código no funcionaría y sería muy difícil averiguar por qué. .addEventListener() sin embargo, arrojaría un error (al menos en Firefox): TypeError: Argumento 2 de EventTarget.addEventListener no es un objeto.
  • No proporciona una forma de elegir si desea manejar el evento en su fase de captura o burbujeo.

Controladores de eventos en línea (onevent Atributo HTML)

Ejemplo de código:

<a href="//google.com" onclick="event.preventDefault();">Try clicking this link.</a>

similar a element.onevent, ahora está desalentado. Además de los problemas que element.onevent tiene, eso:

  • Es un posible problema de seguridad, porque hace XSS mucho más dañino. Hoy en día los sitios web deberían enviar Content-Security-Policy Cabecera HTTP para bloquear scripts en línea y permitir scripts externos solo desde dominios de confianza. Ver ¿Cómo funciona la política de seguridad de contenido?
  • No estructura de documento separada y lógica.
  • Si genera su página con un script del lado del servidor y, por ejemplo, genera cientos de enlaces, cada uno con el mismo manejador de eventos en línea, su código sería mucho más extenso que si el controlador de eventos se definiera solo una vez. Eso significa que el cliente debería descargar más contenido y, como resultado, su sitio web sería más lento.

Ver también


43
2018-01-29 21:01



Mientras onclick funciona en todos los navegadores, addEventListener no funciona en versiones anteriores de Internet Explorer, que utiliza attachEvent en lugar.

La desventaja de onclick es que solo puede haber un controlador de eventos, mientras que los otros dos dispararán todas las devoluciones de llamadas registradas.


16
2018-06-14 18:52



Hasta donde yo sé, el evento de "carga" de DOM todavía funciona muy limitado. Eso significa que solo disparará para el window object, images y <script> elementos por ejemplo. Lo mismo ocurre con el directo onload asignación. No hay diferencia técnica entre esos dos. Probablemente .onload = tiene una mejor disponibilidad entre navegadores.

Sin embargo, no puedes asignar un load event a un <div> o <span> elemento o lo que sea.


12
2017-08-01 17:27



Si no está demasiado preocupado por el soporte del navegador, hay una forma de volver a enlazar la referencia 'this' en la función llamada por el evento. Normalmente señalará el elemento que generó el evento cuando se ejecuta la función, que no siempre es lo que desea. La parte difícil es, al mismo tiempo, poder eliminar el mismo detector de eventos, como se muestra en este ejemplo: http://jsfiddle.net/roenbaeck/vBYu3/

/*
    Testing that the function returned from bind is rereferenceable, 
    such that it can be added and removed as an event listener.
*/
function MyImportantCalloutToYou(message, otherMessage) {
    // the following is necessary as calling bind again does 
    // not return the same function, so instead we replace the 
    // original function with the one bound to this instance
    this.swap = this.swap.bind(this); 
    this.element = document.createElement('div');
    this.element.addEventListener('click', this.swap, false);
    document.body.appendChild(this.element);
}
MyImportantCalloutToYou.prototype = {
    element: null,
    swap: function() {
        // now this function can be properly removed 
        this.element.removeEventListener('click', this.swap, false);           
    }
}

El código anterior funciona bien en Chrome, y es probable que haya alguna solución para hacer que "bind" sea compatible con otros navegadores.


1
2018-03-14 09:36



El uso de controladores en línea es incompatible con Política de seguridad de contenido entonces el addEventListener enfoque es más seguro desde ese punto de vista. Por supuesto, puede habilitar los controladores en línea con unsafe-inline pero, como su nombre lo indica, no es seguro, ya que recupera toda la horda de exploits de JavaScript que impide la CSP.


1
2018-04-20 16:40