Muchas veces he escuchado que usar eventos JavaScript, como onClick()
HTML, es una mala práctica, porque no es bueno para la semántica. Me gustaría saber cuáles son las desventajas y cómo solucionar el siguiente código.
<a href="#" onclick="popup('/map/', 300, 300, 'map'); return false;">link</a>
javascript
html
NiLL
fuente
fuente
#
, cualquiera que elija tener JavaScript deshabilitado se quedará atascado y no podrá hacer nada. Para algunos sitios eso es algo bueno, pero para simplemente abrir una ventana, es completamente estúpido no proporcionar un enlace "real".<button>
, porque se supone que los enlaces apuntan a un recurso real. Es más semántico de esa manera y es más claro para los usuarios de lectores de pantalla.Respuestas:
Probablemente estés hablando de un JavaScript discreto , que se vería así:
con la lógica en un archivo javascript central que se parece a esto:
Las ventajas son
fuente
onClick
. También puede escribir pruebas unitarias si lo desea contra sus scripts, lo que también es muy difícil. Supongo que si el código está dentroonClick
y no hay lógica separada. Personalmente, no tengo ningún problema para depurar JavaScript discreto y los beneficios de administrar y probar el código JavaScript son muy buenos para no usarlos.onclick
puede mapear más explícitamente las relaciones causales entre la interacción del elemento y el efecto (llamada a la función), así como reducir la carga cognitiva. Muchas lecciones arrojan a los alumnos a unaddEventListener
paquete que contiene muchas más ideas dentro de una sintaxis más difícil. Además, los marcos basados en componentes recientes como Riot y React usan elonclick
atributo y están cambiando la noción de lo que debería ser la separación. La transferencia de HTMLonclick
a un componente que admita esto podría ser un proceso de "pasos" más efectivo para el aprendizaje.Si está utilizando jQuery, entonces:
HTML:
JS:
Esto tiene la ventaja de seguir trabajando sin JS, o si el usuario hace clic en el medio del enlace.
También significa que podría manejar ventanas emergentes genéricas reescribiendo nuevamente a:
HTML:
JS:
Esto le permitiría agregar una ventana emergente a cualquier enlace simplemente dándole la clase emergente.
Esta idea podría extenderse aún más así:
HTML:
JS:
¡Ahora puedo usar el mismo código para muchas ventanas emergentes en todo mi sitio sin tener que escribir un montón de cosas onclick! ¡Yay por la reutilización!
También significa que si más tarde decido que las ventanas emergentes son una mala práctica (¡lo que son!) Y que quiero reemplazarlas con una ventana modal de estilo lightbox, puedo cambiar:
a
y todas mis ventanas emergentes en todo mi sitio ahora funcionan de manera totalmente diferente. Incluso podría hacer una detección de funciones para decidir qué hacer en una ventana emergente, o almacenar una preferencia de los usuarios para permitirlos o no. Con el clic en línea, esto requiere una gran copia y un esfuerzo de pegado.
fuente
Con aplicaciones JavaScript muy grandes, los programadores están utilizando más encapsulación de código para evitar contaminar el alcance global. Y para que una función esté disponible para la acción onClick en un elemento HTML, debe estar en el ámbito global.
Es posible que haya visto archivos JS que se parecen a esto ...
Estas son expresiones de función invocadas inmediatamente (IIFE) y cualquier función declarada dentro de ellas solo existirá dentro de su alcance interno.
Si declara
function doSomething(){}
dentro de un IIFE, luego realizadoSomething()
la acción onClick de un elemento en su página HTML, obtendrá un error.Si, por otro lado, crea un EventListener para ese elemento dentro de ese IIFE y llama
doSomething()
cuando el oyente detecta un evento de clic, es bueno porque el oyente ydoSomething()
comparte el alcance del IIFE.Para pequeñas aplicaciones web con una cantidad mínima de código, no importa. Pero si aspira a escribir bases de código grandes y fáciles de mantener,
onclick=""
es un hábito que debe evitar.fuente
No es bueno por varias razones:
eval
Lo más simple sería agregar un
name
atributo a su<a>
elemento, luego podría hacer:aunque la mejor práctica moderna sería usar un en
id
lugar de un nombre, y usar enaddEventListener()
lugar de usaronclick
ya que eso le permite vincular múltiples funciones a un solo evento.fuente
addEventListener()
y por qué.Hay unas pocas razones:
Me parece que ayuda a mantener el marcado separado, es decir, los scripts HTML y del lado del cliente. Por ejemplo, jQuery facilita la adición de controladores de eventos mediante programación.
El ejemplo que proporcione se rompería en cualquier agente de usuario que no sea compatible con JavaScript o que tenga JavaScript desactivado. El concepto de mejora progresiva fomentaría un hipervínculo simple
/map/
para los agentes de usuario sin javascript, y luego agregaría un controlador de clics de forma protocolaria para los agentes de usuario que admitan javascript.Por ejemplo:
Margen:
Javascript:
fuente
<a href="https://stackoverflow.com/map/" onclick="popup('/map/', 300, 300, 'map'); return false;">link</a>
Revisión
El enfoque discreto de JavaScript fue bueno en el PASADO, especialmente el enlace de controlador de eventos en HTML se consideró una mala práctica (principalmente porque
onclick events run in the global scope and may cause unexpected error
lo mencionado por YiddishNinja )Sin embargo...
Actualmente parece que este enfoque está un poco desactualizado y necesita alguna actualización. Si alguien quiere ser un desarrollador frontend profesional y escribir aplicaciones grandes y complicadas, entonces necesita usar marcos como Angular, Vue.js, etc. Sin embargo, esos marcos generalmente usan (o permiten usar) plantillas HTML donde los controladores de eventos están vinculados en el código html-template directamente y esto es muy útil, claro y efectivo, por ejemplo, en la plantilla angular la gente suele escribir:
En raw js / html el equivalente de esto será
La diferencia es que en el
onclick
evento js sin procesar se ejecuta en el ámbito global, pero los marcos proporcionan la encapsulación.¿Entonces, dónde está el problema?
El problema es cuando un programador novato que siempre escuchó que html-onclick es malo y que siempre usa
btn.addEventListener("onclick", ... )
quiere usar un marco con plantillas (addEventListener
también tiene inconvenientes , si actualizamos DOM usando dinámicamenteinnerHTML=
(lo cual es bastante rápido ), entonces perdemos eventos los manejadores se unen de esa manera). Luego se enfrentará a algo como malos hábitos o enfoque incorrecto para el uso del marco, y usará el marco de una manera muy mala, porque se centrará principalmente en la parte js y no en la parte de la plantilla (y producirá poco claro y difícil de mantener código). Para cambiar estos hábitos, perderá mucho tiempo (y probablemente necesitará algo de suerte y un maestro).En mi opinión, según la experiencia con mis alumnos, sería mejor para ellos si utilizan html-handlers-bind al principio. Como digo, es cierto que los controladores son de alcance global, pero en esta etapa los estudiantes generalmente crean pequeñas aplicaciones que son fáciles de controlar. Para escribir aplicaciones más grandes, eligen algunos marcos.
¿Entonces lo que hay que hacer?
Podemos ACTUALIZAR el enfoque de JavaScript discreto y permitir controladores de eventos de enlace (eventualmente con parámetros simples) en html (pero solo controlador de enlace, no poner lógica en onclick como en la pregunta OP). Entonces, en mi opinión en js / html sin procesar, esto debería permitirse
o
Mostrar fragmento de código
Pero los ejemplos a continuación NO deberían permitirse
La realidad cambia, nuestro punto de vista también debería
fuente
addEventListener
. Anuncio 2. Sí, pueden sobrescribirse (aunque generalmente nadie lo hace): ¿dónde está el problema? Anuncio 3. El controlador no se activará después de eliminar onclick attrib - prueba aquíEs un
nuevoparadigma llamado " JavaScript discreto ". El "estándar web" actual dice separar la funcionalidad y la presentación.No es realmente una "mala práctica", es solo que la mayoría de los estándares nuevos quieren que uses oyentes de eventos en lugar de JavaScript en línea.
Además, esto puede ser algo personal, pero creo que es mucho más fácil de leer cuando usa oyentes de eventos, especialmente si tiene más de 1 declaración de JavaScript que desea ejecutar.
fuente
Su pregunta desencadenará la discusión, supongo. La idea general es que es bueno separar el comportamiento y la estructura. Además, afaik, un controlador de clics en línea tiene que ser
eval
'convertido' en una verdadera función de JavaScript. Y es bastante anticuado, aunque ese es un argumento bastante inestable. Ah, bueno, lee algo al respecto @ quirksmode.orgfuente
rendimiento y la eficiencia.
fuente
Dos razones más para no usar controladores en línea:
Pueden requerir problemas tediosos de escape de cotizaciones
Dada una arbitraria cadena, si usted quiere ser capaz de construir un controlador de línea que llama a una función con la cadena, por la solución general, que tendrá que escapar de los atributos delimitadores (con la entidad HTML asociado), y se le tiene que escapar del delimitador utilizado para la cadena dentro del atributo, como el siguiente:
Eso es increíblemente feo. En el ejemplo anterior, si no reemplazó la
'
s, se produciría un SyntaxError, porquealert('foo'"bar')
no es una sintaxis válida. Si no reemplazó el"
s, entonces el navegador lo interpretaría como un fin alonclick
atributo (delimitado con"
s arriba), que también sería incorrecto.Si uno usa habitualmente manipuladores en línea, debe asegurarse de recordar hacer algo similar a lo anterior (y hacerlo bien ) cada vez , lo cual es tedioso y difícil de entender de un vistazo. Es mejor evitar los controladores en línea por completo para que la cadena arbitraria se pueda usar en un cierre simple:
¿No es eso mucho mejor?
La cadena de alcance de un controlador en línea es extremadamente peculiar
¿Qué crees que registrará el siguiente código?
Pruébalo, ejecuta el fragmento. Probablemente no sea lo que estabas esperando. ¿Por qué produce lo que hace? Porque los manejadores en línea se ejecutan dentro de
with
bloques. El código anterior está dentro de treswith
bloques: uno para eldocument
, uno para el<form>
y otro para el<button>
:Mostrar fragmento de código
Como
disabled
es una propiedad del botón, la referenciadisabled
dentro del controlador en línea se refiere a la propiedad del botón, no a ladisabled
variable externa . Esto es bastante contrario a la intuición.with
tiene muchos problemas: puede ser la fuente de errores confusos y ralentiza significativamente el código. Ni siquiera está permitido en modo estricto. Pero con los controladores en línea, se ve obligado a ejecutar el código a través dewith
s, y no solo a través de unowith
, sino a través de múltipleswith
s anidados . Es una locura.with
nunca debe usarse en código. Debido a que los controladores en línea requieren implícitamentewith
junto con todo su comportamiento confuso, también deben evitarse los controladores en línea.fuente