¿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 en un archivo .js separado, y ambos funcionan perfectamente.
¿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 en un archivo .js separado, y ambos funcionan perfectamente.
Respuestas:
Ambos son correctos, pero ninguno de ellos es el "mejor" per se, y puede haber una razón por la cual el desarrollador eligió usar ambos enfoques.
Oyentes de eventos (addEventListener y IE's attachEvent)
Las versiones anteriores de Internet Explorer implementan JavaScript de manera diferente a casi cualquier otro navegador. Con versiones inferiores a la 9, utiliza el método attachEvent
[ doc ], de esta manera:
element.attachEvent('onclick', function() { /* do stuff here*/ });
En la mayoría de los otros navegadores (incluido IE 9 y superior), utiliza addEventListener
[ doc ], de esta manera:
element.addEventListener('click', function() { /* do stuff here*/ }, false);
Con este enfoque ( eventos DOM Nivel 2 ), 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 otros problemas 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 utilizando 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 reacciona el oyente a los eventos burbujeantes [ doc ]. He pasado falso en los ejemplos, que es estándar para probablemente el 95% de los casos de uso. No hay 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 que admiten 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 hace el trabajo; Es simple y directo. No puede usar cierres o funciones anónimas aquí (aunque el controlador en sí mismo es una función anónima), y su control del 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 de funciones y / o cierres.
El inconveniente significativo de los eventos en línea es que, a diferencia de los oyentes de eventos descritos anteriormente, es posible que solo se le asigne un evento en línea. Los eventos en línea se almacenan como un atributo / propiedad del elemento [ doc ], lo que significa que se puede sobrescribir.
Usando el ejemplo <a>
del HTML anterior:
var element = document.getElementById('testing');
element.onclick = function () { alert('did stuff #1'); };
element.onclick = function () { alert('did stuff #2'); };
... cuando hace clic en el elemento, solo verá "Did stuff # 2": sobrescribió la primera onclick
propiedad asignada con el segundo valor y sobrescribió la onclick
propiedad HTML original en línea . Compruébalo aquí: http://jsfiddle.net/jpgah/ .
En términos generales, no use eventos en línea . Puede haber casos de uso específicos para él, pero si no está 100% seguro de tener ese caso de uso, entonces no debe ni debe usar eventos en línea.
Javascript moderno (angular y similar)
Desde que esta respuesta se publicó originalmente, los marcos de JavaScript como Angular se han vuelto mucho más populares. Verá un código como este en una plantilla angular:
<button (click)="doSomething()">Do Something</button>
Esto parece un evento en línea, pero no lo es. Este tipo de plantilla se trasladará a un código más complejo que utiliza oyentes de eventos detrás de escena. Todo lo que he escrito sobre los eventos aquí todavía se aplica, pero al menos una capa lo elimina del meollo de la cuestión. Debe comprender los aspectos básicos, pero si las mejores prácticas de su marco JS moderno implican escribir este tipo de código en una plantilla, no sienta que está utilizando un evento en línea, no lo está.
¿Cuál es el mejor?
La pregunta es una cuestión de compatibilidad y necesidad del navegador. ¿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. De lo contrario, puede parecer que un evento en línea funcionaría, pero es mucho mejor que se prepare para un futuro que, aunque parezca poco probable, es predecible al menos. Existe la posibilidad de que tenga que pasar a los oyentes de eventos basados en JS, por lo que también puede comenzar allí. No use eventos en línea.
jQuery y otros marcos javascript encapsulan las diferentes implementaciones de navegador de eventos DOM de nivel 2 en modelos genéricos para que pueda escribir código compatible entre navegadores sin tener que preocuparse por la historia de IE como rebelde. Mismo código con jQuery, todos los navegadores cruzados y listo para rockear:
$(element).on('click', function () { /* do stuff */ });
Sin embargo, no se quede sin obtener un marco solo para esto. Puede rodar fácilmente su propia pequeña utilidad para cuidar 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!'); }
);
Pruébalo: http://jsfiddle.net/bmArj/
Teniendo todo eso en cuenta, a menos que el script que está viendo tome en cuenta las diferencias del navegador de otra manera (en el código que no se muestra en su pregunta), el uso de la parte addEventListener
no funcionaría en versiones de IE menores de 9.
Documentación y lectura relacionada
function addEvent(e,n,f){return e.attachEvent?e.attachEvent('on'+n,f):e.addEventListener(n,f,!!0)}
<< Con 98 caracteres, ¡este es más de un 40% más pequeño!
La diferencia que podría ver si tuviera otro par de 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 se debe a addEventListener
que no sobrescribe los controladores de eventos existentes, mientras que onclick
anula cualquier onclick = fn
controlador de eventos existente .
La otra diferencia significativa, por supuesto, es que onclick
siempre funcionará, mientras addEventListener
que no funciona en Internet Explorer antes de la versión 9. Puede usar el análogo attachEvent
(que tiene una sintaxis ligeramente diferente) en IE <9.
En esta respuesta, describiré los tres métodos para definir controladores de eventos DOM.
element.addEventListener()
Ejemplo de código:
element.addEventListener()
tiene múltiples ventajas:
element.removeEventListener()
.useCapture
parámetro, que indica si desea manejar el evento en su fase de captura o burbujeo . Ver: No se puede entender el atributo useCapture en addEventListener ..onevent
propiedades de los elementos DOM, muchos programadores de JavaScript sin experiencia piensan que el nombre del evento es, por ejemplo, onclick
o onload
. noon
es parte del nombre del evento . Los nombres de eventos correctos son click
y load
, y así es como se pasan los nombres de eventos .addEventListener()
.element.onevent = function() {}
(por ejemplo onclick
, onload
)Ejemplo de código:
Esta era una forma de registrar controladores de eventos en DOM 0. Ahora se desaconseja, porque:
onevent
propiedad a su estado inicial (es decir null
).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: Argument 2 de EventTarget.addEventListener no es un objeto .onevent
atributo HTML)Ejemplo de código:
De manera similar a element.onevent
, ahora se desaconseja. Además de los problemas que element.onevent
tiene, esto:
Content-Security-Policy
encabezado HTTP adecuado para bloquear los scripts en línea y permitir scripts externos solo desde dominios de confianza. Consulte ¿Cómo funciona la Política de seguridad de contenido?Si bien onclick
funciona en todos los navegadores, addEventListener
no funciona en versiones anteriores de Internet Explorer, que utiliza en su attachEvent
lugar.
La desventaja onclick
es que solo puede haber un controlador de eventos, mientras que los otros dos dispararán todas las devoluciones de llamada registradas.
Hasta donde yo sé, el evento de "carga" DOM todavía funciona muy limitado. Eso significa que sólo va a disparar para el window object
, images
y <script>
los elementos, por ejemplo. Lo mismo ocurre con la onload
asignación directa . No hay diferencia técnica entre esos dos. Probablemente .onload =
tiene una mejor disponibilidad entre navegadores.
Sin embargo, no se puede asignar una load event
a una <div>
o <span>
elemento o lo que sea.
addEventListener
puede agregar múltiples eventos, mientras que con onclick
esto no se puede hacer.onclick
se puede agregar como un HTML
atributo, mientras que an addEventListener
solo se puede agregar dentro de los <script>
elementos.addEventListener
puede tomar un tercer argumento que puede detener la propagación del evento.Ambos se pueden usar para manejar eventos. Sin embargo, addEventListener
debería ser la opción preferida ya que puede hacer todo lo que onclick
hace y más. No use en línea onclick
como atributos HTML, ya que esto mezcla el javascript y el HTML, lo cual es una mala práctica. Hace que el código sea menos mantenible.
onclick
manipuladores en línea por temor a que me hagan reír fuera de la sala, pero por lo general, los eventos están ligados en formas mucho peores y menos difíciles en los últimos años. Las clases como js-link
, js-form-validation
o atributos de datos con data-jspackage="init"
no es en absoluto nada mejor ... Y cómo ofteen es lo que realmente utilizan el burbujeo de eventos? A mí personalmente me encantaría poder escribir un controlador sin verificar si el objetivo realmente coincide con mi elemento, o tener que detener la propagación en varios lugares debido a errores aleatorios.
Todavía no se ha notado un detalle: los navegadores de escritorio modernos consideran que las diferentes pulsaciones de botones son "clics" para AddEventListener('click'
y onclick
por defecto.
onclick
y AddEventListener
haga clic en disparar en el clic izquierdo y medio.onclick
activa solo con el clic izquierdo, pero el AddEventListener
clic se activa con los clics izquierdo, medio y derecho.Además, el comportamiento del clic con el botón central es muy inconsistente en todos los navegadores cuando están involucrados los cursores de desplazamiento:
También vale la pena señalar que los eventos de "clic" para cualquier elemento HTML seleccionable por teclado, como input
también disparar al espacio o ingresar cuando se selecciona el elemento.
Javascript tiende a mezclar todo en objetos y eso puede hacerlo confuso. Todo en uno es la forma de JavaScript.
Esencialmente onclick es un atributo HTML. Por el contrario, addEventListener es un método en el objeto DOM que representa un elemento HTML.
En los objetos de JavaScript, un método es simplemente una propiedad que tiene una función como valor y que funciona contra el objeto al que está asociado (utilizando esto, por ejemplo).
En JavaScript, el elemento HTML representado por DOM tendrá sus atributos asignados a sus propiedades.
Aquí es donde la gente se confunde porque JavaScript combina todo en un solo contenedor o espacio de nombres sin capa de indirección.
En un diseño OO normal (que al menos combina el espacio de nombres de propiedades / métodos), podría tener algo como:
domElement.addEventListener // Object(Method)
domElement.attributes.onload // Object(Property(Object(Property(String))))
Hay variaciones como que podría usar un getter / setter para onload o HashMap para atributos, pero en última instancia, así es como se vería. JavaScript eliminó esa capa de indirección con la expectativa de saber qué es qué, entre otras cosas. Fusionó domElement y atributos juntos.
Salvo compatibilidad, como práctica recomendada debe usar addEventListener. Como otras respuestas hablan sobre las diferencias a ese respecto en lugar de las diferencias programáticas fundamentales, lo renunciaré. Esencialmente, en un mundo ideal, solo debes usar * desde HTML, pero en un mundo aún más ideal no deberías hacer algo así desde HTML.
¿Por qué es dominante hoy? Es más rápido de escribir, más fácil de aprender y tiende a funcionar.
El punto principal de la carga en HTML es dar acceso al método o funcionalidad addEventListener en primer lugar. Al usarlo en JS, está pasando por HTML cuando podría estar aplicándolo directamente.
Hipotéticamente puedes hacer tus propios atributos:
$('[myclick]').each(function(i, v) {
v.addEventListener('click', function() {
eval(v.myclick); // eval($(v).attr('myclick'));
});
});
Lo que JS hace con es un poco diferente a eso.
Puede equipararlo a algo como (por cada elemento creado):
element.addEventListener('click', function() {
switch(typeof element.onclick) {
case 'string':eval(element.onclick);break;
case 'function':element.onclick();break;
}
});
Los detalles de implementación reales probablemente diferirán con una gama de variaciones sutiles que los hacen ligeramente diferentes en algunos casos, pero esa es la esencia de esto.
Podría decirse que es un truco de compatibilidad que puede anclar una función a un atributo on ya que, por defecto, los atributos son todas cadenas.
Según MDN , la diferencia es la siguiente:
addEventListener:
El método EventTarget.addEventListener () agrega el objeto compatible con EventListener especificado a la lista de oyentes de eventos para el tipo de evento especificado en EventTarget en el que se llama. El objetivo del evento puede ser un Elemento en un documento, el Documento en sí, una Ventana o cualquier otro objeto que admita eventos (como XMLHttpRequest).
al hacer clic:
La propiedad onclick devuelve el código del controlador de eventos click en el elemento actual. Cuando use el evento click para activar una acción, también considere agregar esta misma acción al evento keydown, para permitir el uso de esa misma acción por personas que no usan un mouse o una pantalla táctil. Sintaxis element.onclick = functionRef; donde functionRef es una función, a menudo el nombre de una función declarada en otro lugar o una expresión de función. Consulte "Guía de JavaScript: Funciones" para más detalles.
También hay una diferencia de sintaxis en uso como se ve en los siguientes códigos:
addEventListener:
// Function to change the content of t2
function modifyText() {
var t2 = document.getElementById("t2");
if (t2.firstChild.nodeValue == "three") {
t2.firstChild.nodeValue = "two";
} else {
t2.firstChild.nodeValue = "three";
}
}
// add event listener to table
var el = document.getElementById("outside");
el.addEventListener("click", modifyText, false);
al hacer clic:
function initElement() {
var p = document.getElementById("foo");
// NOTE: showAlert(); or showAlert(param); will NOT work here.
// Must be a reference to a function name, not a function call.
p.onclick = showAlert;
};
function showAlert(event) {
alert("onclick Event detected!");
}
Si no está demasiado preocupado por la compatibilidad del navegador, hay una manera de volver a vincular la referencia 'this' en la función llamada por el evento. Normalmente apuntará al elemento que generó el evento cuando se ejecuta la función, que no siempre es lo que desea. La parte difícil es poder al mismo tiempo eliminar el mismo oyente 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 algunas dudas al hacer que "bind" sea compatible con otros navegadores.
El uso de controladores en línea es incompatible con la Política de seguridad de contenido, por lo que 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 todas las hordas de exploits de JavaScript que CSP previene.
También debería ser posible extender el oyente mediante la creación de un prototipo (si tenemos una referencia a él y no es una función anónima), o hacer que 'onclick' llame a una biblioteca de funciones (una función que llama a otras funciones)
me gusta
elm.onclick = myFunctionList
function myFunctionList(){
myFunc1();
myFunc2();
}
Esto significa que nunca tenemos que evitar la llamada onclick, solo alterar la función myFunctionList () para hacer lo que queramos, pero esto nos deja sin control de las fases de burbujeo / captura, por lo que debería evitarse para los navegadores más nuevos.
por si alguien encuentra este hilo en el futuro ...
element.onclick = function () {/ * do stuff * /}
element.addEventListener ('click', function () {/ * do stuff * /}, false);
Aparentemente hacen lo mismo: escuchan el evento click y ejecutan una función de devolución de llamada. Sin embargo, no son equivalentes. Si alguna vez necesita elegir entre los dos, esto podría ayudarlo a determinar cuál es el mejor para usted.
La principal diferencia es que onclick es solo una propiedad y, como todas las propiedades de los objetos, si escribe más de una vez, se sobrescribirá . En cambio, con addEventListener () , simplemente podemos vincular un controlador de eventos al elemento, y podemos llamarlo cada vez que lo necesitemos sin preocuparnos por las propiedades sobrescritas. El ejemplo se muestra aquí,
Pruébalo: https://jsfiddle.net/fjets5z4/5/
En primer lugar, tuve la tentación de seguir usando onclick, porque es más corto y parece más simple ... y de hecho lo es. Pero ya no recomiendo usarlo. Es como usar JavaScript en línea. El uso de algo como, eso es JavaScript en línea, es altamente desaconsejado hoy en día (también se desaconseja CSS en línea, pero ese es otro tema).
Sin embargo, la función addEventListener (), a pesar de ser el estándar, simplemente no funciona en los navegadores antiguos (Internet Explorer debajo de la versión 9), y esta es otra gran diferencia. Si necesita admitir estos navegadores antiguos, debe seguir el camino de hacer clic. Pero también podría usar jQuery (o una de sus alternativas): básicamente simplifica su trabajo y reduce las diferencias entre los navegadores, por lo tanto, puede ahorrarle mucho tiempo.
var clickEvent = document.getElementByID("onclick-eg");
var EventListener = document.getElementByID("addEventListener-eg");
clickEvent.onclick = function(){
window.alert("1 is not called")
}
clickEvent.onclick = function(){
window.alert("2 is not called")
}
EventListener.addEventListener("click",function(){
window.alert("1 is called")
})
EventListener.addEventListener("click",function(){
window.alert("2 is also called")
})
addEventListener
le permite configurar múltiples manejadores, pero no es compatible con IE8 o inferior.
IE sí attachEvent
, pero no es exactamente lo mismo.
El contexto al que hace referencia la 'this'
palabra clave en JavasSript es diferente.
mira el siguiente código:
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title></title>
</head>
<body>
<input id="btnSubmit" type="button" value="Submit" />
<script>
function disable() {
this.disabled = true;
}
var btnSubmit = document.getElementById('btnSubmit');
btnSubmit.onclick = disable();
//btnSubmit.addEventListener('click', disable, false);
</script>
</body>
</html>
Lo que hace es realmente simple. Cuando hace clic en el botón, el botón se desactivará automáticamente.
Primero, cuando intente conectar los eventos de esta manera, el button.onclick = function(),
evento onclick se activará haciendo clic en el botón, sin embargo, el botón no se deshabilitará porque no hay un enlace explícito entre button.onclick y el controlador de eventos onclick. Si depura ver el 'this'
objeto, puede ver que se refiere al 'window'
objeto.
En segundo lugar, si comenta btnSubmit.onclick = disable();
y descomenta
//btnSubmit.addEventListener('click', disable, false);
, puede ver que el botón está deshabilitado porque de esta manera hay un enlace explícito entre el evento button.onclick y el controlador de eventos onclick. Si depura en la función de deshabilitación, puede ver las 'this'
referencias en button control
lugar de las window
.
Esto es algo que no me gusta de JavaScript, que es inconsistencia. Por cierto, si está utilizando jQuery ( $('#btnSubmit').on('click', disable);
), utiliza el enlace explícito.
btnSubmit.onclick = disable;
(asignar función, no llamarla). Luego, en ambos casos this
se referirá al elemento del botón.
onclick es básicamente un addEventListener que realiza específicamente una función cuando se hace clic en el elemento. Por lo tanto, es útil cuando tiene un botón que realiza operaciones simples, como un botón de calculadora. addEventlistener se puede usar para una multitud de cosas, como realizar una operación cuando se carga DOM o todo el contenido, similar a window.onload pero con más control.
Tenga en cuenta que en realidad puede usar más de un evento en línea, o al menos usando onclick separando cada función con un punto y coma, como este ...
No escribiría una función en línea, ya que podría tener problemas más adelante y sería desordenado. Solo utilícelo para llamar a funciones ya realizadas en su archivo de script.
El que uses supongo que dependerá de lo que quieras. addEventListener para operaciones complejas y onclick para simples. He visto que algunos proyectos no adjuntan uno específico a los elementos y, en cambio, implementarían un escucha de eventos más global que determinaría si un toque en un botón y realizaría ciertas tareas dependiendo de lo que se presionó. Imo que podría conducir a problemas, creo, y aunque pequeño, probablemente, un desperdicio de recursos si ese oyente de eventos tuviera que manejar cada clic
function addEvent(element, myEvent, fnc) { return ((element.attachEvent) ? element.attachEvent('on' + myEvent, fnc) : element.addEventListener(myEvent, fnc, false)); }