Se supone que casi todo lo que haces en JavaScript comienza cuando algo sucede: el usuario hace clic en un botón, se desplaza sobre un menú, presiona una tecla y obtienes la idea. Es bastante simple de hacer con bibliotecas como jQuery, pero ¿sabes cómo conectar eventos en JavaScript en bruto? Hoy te voy a enseñar justo eso.!
Manejar eventos de JavaScript no es ciencia espacial. Por supuesto, hay diferencias en el navegador (¿qué esperabas?), Pero una vez que lo entiendas y construyas tus propias funciones de ayuda para igualar el campo de juego, te alegrarás de saberlo. Incluso si aún planeas usar una biblioteca para este tipo de cosas, es bueno saber qué está pasando debajo de la superficie. Aquí vamos.
El manejo de eventos más básico en JavaScript es el manejo de eventos de nivel 0. Es bastante fácil: simplemente asigne su función a la propiedad del evento en el elemento. Observar:
var element = document.getElementById ('myElement'); element.onclick = function () alert ('your function here'); ;
Una vez que tengo el elemento, configuro el al hacer clic
Propiedad igual a una función. Ahora, cuando elemento
se hace clic, esa función se ejecutará y veremos un cuadro de alerta.
Pero como sabia usar al hacer clic
? Puede obtener una lista de los eventos disponibles en Wikipedia. La belleza del método del Nivel 0 es que es compatible con todos los navegadores que se utilizan hoy en día. El inconveniente es que solo puede registrar cada evento una vez con cada elemento. Así que esto solo causará una alerta:
element.onclick = function () alert ('function 1'); ; element.onclick = function () alert ('I override function 1');
Solo se ejecutará la segunda función cuando se haga clic en el elemento, ya que reasignamos la propiedad onclick. Para eliminar un controlador de eventos, simplemente podemos establecerlo en nulo.
element.onclick = null;
Aunque solo proporciona una funcionalidad básica, el soporte consistente en todos los navegadores hace que el manejo de eventos de Nivel 0 sea una opción válida para proyectos súper simples.
Ahora que se está calentando en eventos de JavaScript, analicemos dos facetas importantes antes de pasar a mejores técnicas: el objeto de evento y el esta
palabra clave. Cuando se ejecuta un evento, hay mucha información sobre el evento que tal vez quiera saber: ¿qué tecla se presionó? ¿En qué elemento se hizo clic? ¿El usuario hizo clic con el botón izquierdo, derecho o central? Todos estos datos y más se almacenan en un objeto de evento. Para todos los navegadores excepto Internet Explorer, puede acceder a este objeto pasándolo como un parámetro a la función de manejo. En IE, puedes obtenerlo desde la variable global evento de ventana
. No es difícil resolver esta diferencia..
función myFunction (evt) evt = evt || window.event; / *… * / Element.onclick = myFunction;
mi función
toma el parámetro de evento para todos los buenos navegadores, y lo reasignamos a evento de ventana
Si Evt
no existe Veremos algunas de las propiedades del objeto de evento un poco más tarde..
los esta
El trabajo clave es importante dentro de las funciones de manejo de eventos; Se refiere al elemento que recibió el evento..
element.onclick = function () this.style.backgroundColor = 'red'; // igual que element.style.backgroundColor = 'red';
Desafortunadamente, en Internet Explorer, esta
no se refiere al elemento actuado; se refiere al objeto de la ventana. Eso es inútil, pero veremos una manera de remediar eso en un momento..
El manejo de eventos de Nivel 2 es la especificación W3C para eventos DOM. Es bastante simple, en realidad.
element.addEventListener ('mouseover', myFunction, false);
El metodo se llama addEventListener
. El primer parámetro es el tipo de evento que queremos escuchar. Por lo general, es el mismo nombre que los eventos de nivel 0, sin el prefijo 'on'. El segundo parámetro es un nombre de función o la función en sí. El parámetro final determina si capturamos o no; discutiremos esto en un momento.
Uno de los grandes beneficios de usar addEventListener
es que ahora podemos asignar múltiples eventos para un solo evento en un solo elemento:
element.addEventListener ('dblclick', logSuccessToConsole, false); element.addEventListener ('dblclick', function () console.log ('esta función no reemplaza la primera.');, false);
Para eliminar estos manejadores, usa la función removeEventListener
. Entonces, para eliminar la función que agregamos arriba, hacemos esto:
element.removeEventListener ('dblclick', logSuccessToConsole, false);
El parámetro final en addEventListner
y removeEventListener
es un booleano que define si desencadenamos el evento en la etapa de captura o propagación. Esto es lo que eso significa:
Cuando haces clic en un elemento, también haces clic en cada uno de sus elementos ancestrales.
Guardar trabajo
Si hago clic en el lapso # guardar
, También he hecho clic div # barra de herramientas
, div # wrapper
, y cuerpo
. Entonces, si alguno de estos elementos tiene escuchas de eventos que escuchan clics, se llamarán sus funciones respectivas. Pero, ¿en qué orden deben llamarse? Eso es lo que decide el último parámetro. En la especificación W3C, nuestro evento de clics comenzaría en el cuerpo
y bajar por la cadena hasta llegar a la lapso # guardar
; Esa es la etapa de captura. Entonces, va desde la lapso # guardar
copia de seguridad a la cuerpo
; Esa es la etapa burbujeante. Esto es fácil de recordar, porque las burbujas flotan hacia arriba. No todos los eventos burbujean; esa tabla de Wikipedia te dirá cuáles hacen y cuáles no.
Así que si el parámetro de captura se establece en cierto
, el evento se activará en el camino hacia abajo; si está configurado para falso
, Se activará en el camino hacia arriba..
Es posible que haya notado que, hasta ahora, todos mis ejemplos han establecido la captura en falso, por lo que el evento se activa en la etapa de propagación. Esto se debe a que Internet Explorer no tiene una fase de captura. En IE, solo eventos burbuja..
IE tiene su propia forma de trabajar con eventos. Usa adjuntar
.
element.attachEvent ('onclick', runThisFunction);
Ya que los eventos de IE solo burbujean, no necesitas la tercera variable. Los dos primeros son los mismos que con addEventListener
, con la gran excepción de que IE requiere ese prefijo 'on' para el tipo de evento. Por supuesto, puede asignar múltiples eventos de un tipo a un elemento individual con este modelo. Para eliminar eventos, use separar
.
element.detachEvent ('onclick', runThisFunction);
¿Qué pasa si sus elementos no quieren que sus padres se enteren de sus eventos? No es difícil esconderse. En IE, usas el cancelBubble
Propiedad en el objeto de evento que se pasa a la función llamada. Para el resto, puede utilizar el detener la propagación
Método, también en el objeto de evento..
e.cancelBubble = true; if (e.stopPropagation) e.stopPropagation ();
los detener la propagación
El método también detendrá eventos en sus pistas durante la etapa de captura..
Estaría dispuesto a apostar a que la mayoría de las propiedades en el objeto de evento no se utilizarán, pero hay algunas que usted considera de gran valor. Echemos un vistazo a esos pocos.
los objetivo
La propiedad es el elemento más profundo en el que se hizo clic. En la imagen de arriba, puedes ver que hice clic. botón h1 #
. En IE, esta propiedad se llama srcElement
; para llegar a esta propiedad, haz algo como esto:
var target = e.target || e.srcElement;
los objetivo actual
La propiedad es el elemento que tiene el evento en este momento. En esa captura de pantalla, la objetivo actual
es div # wrapper
. Esto significa que hice clic botón h1 #
, pero el objeto de evento se registró en la consola en la función llamada por el div # wrapper
oyente del evento.
Pero esto te lanzará para un bucle: IE no tiene una propiedad currentTarget, ni nada parecido. Recordando el hecho de que IE ni siquiera deja esta
al igual que el elemento que desencadena el evento, esto significa que no tenemos forma de obtener el elemento que desencadenó el evento cuando se está formando burbujas (lo que significa que se hizo clic en un descendiente del elemento). ¿Confuso? Tal vez un ejemplo ayude: si, en Internet Explorer, tenemos este HTML ...
Botón
... y este controlador de eventos ...
var par = document.getElementById ('parent'); parent.attachEvent ('onclick', doSomething);
... entonces, cuando hacemos clic en el lapso # niño
y el evento burbujea hasta div # padre
, No tenemos camino desde dentro de la función. hacer algo
para llegar al elemento (en este caso, div # padre
) el evento fue activado en.
Hay otras propiedades en el objeto de evento que encontrará útiles, según el caso. En un evento de teclado, (keyup, keydown, keypress) se mostrará el clave
y el CharCode
. Podrá saber si el usuario presionó la tecla alt, shift o ctrl (cmd) mientras presiona / hace clic. Explore los objetos de eventos de diferentes eventos y vea con qué tiene que trabajar!
Hemos encontrado dos problemas principales en nuestro estudio de eventos hasta ahora.
objetivo actual
propiedad, y la esta
objeto hace referencia al objeto ventana.Para resolver estos problemas, construyamos dos funciones con compatibilidad con varios navegadores, una para conectar eventos y otra para eliminarlos.
Vamos a empezar con Añadir evento
; Aquí está la primera ronda:
var addEvent = function (element, type, fn) if (element.attachEvent) element.attachEvent ('on' + type, fn); else element.addEventListener (type, fn, false);
Estoy asignando una función anónima a la variable Añadir evento
Por razones que verás en un minuto. Todo lo que tenemos que hacer es verificar si el elemento tiene la adjuntar
método. Si lo hace, estamos en IE y usaremos ese método. Si no, podemos usar addEventListener
.
Sin embargo, esto no soluciona el hecho de que no tenemos forma de acceder al elemento principal del evento en IE. Para hacer esto, haremos de la función un atributo en el elemento; De esa manera, se percibe como un método del elemento, y esta
será igual al elemento. Sí, lo sé, brillante, ¿verdad? Bueno, no puedo tomar ningún crédito: esta idea proviene de una publicación de blog de John Resig.
var addEvent = function (element, type, fn) if (element.attachEvent) element ['e' + type + fn] = fn; element [type + fn] = function () element ['e' + type + fn] (window.event); element.attachEvent ('on' + tipo, elemento [tipo + fn]); else element.addEventListener (type, fn, false);
La primera línea extra (elemento ['e' + tipo + fn] = fn;
) hace que la función sea un método del elemento, de modo que esta
ahora será igual al elemento. La segunda línea es una función que ejecuta el método, pasando el objeto window.event. Esto le ahorra el paso adicional de verificar el parámetro de objeto de evento dentro de su función. Finalmente, note que hemos cambiado el parámetro de función en adjuntar
método para elemento [tipo + fn]
.
Eso resuelve nuestros dos problemas. Ahora podemos usar nuestro Añadir evento
Funciona en todos los navegadores con la mayor experiencia posible. Pero hay una pequeña optimización que nos gustaría hacer..
Tenga en cuenta que cada vez que nuestro Añadir evento
Se llama función, se comprueba la adjuntar
método. No hay ninguna razón por la que debamos verificar esto más de una vez, sin importar cuántos eventos deseamos registrar. Podemos usar un truco ingenioso que nos permitirá reescribir Añadir evento
.
var addEvent = function (el, type, fn) if (el.attachEvent) addEvent = function (el, type, fn) el ['e' + type + fn] = fn; el [type + fn] = function () el ['e' + type + fn] (window.event); ; el.attachEvent ('on' + type, el [type + fn]); else else addEvent = function (el, type, fn) el.addEventListener (type, fn, false); addEvent (el, type, fn);
Ahora, si el Añadir evento
Se encuentra el método, re-escribiremos. Añadir evento
solo para incluir las partes de IE; Si no, simplemente incluiremos las partes buenas del navegador..
Nuestro eliminarEvento
La función será muy similar:
var removeEvent = function (element, type, fn) if (element.detachEvent) removeEvent = function (element, type, fn) element.detachEvent ('on' + type, el [type + fn]); elemento [tipo + fn] = nulo; else else (removeEvent = function (element, type, fn) element.removeEventListener (type, fn, false); removeEvent (elemento, tipo, fn);
Eso es todo para nuestras funciones de eventos de navegadores cruzados. Sin embargo, hay una cosa que no me gusta de ellos: las funciones no son métodos de los elementos; en cambio, el elemento es un parámetro. Sé que es solo una cuestión de estilo, pero me gusta
btn.addEvent ('click', doThis);
mejor que
addEvent (btn, 'click', doThis);
Podríamos hacer esto envolviendo nuestras funciones en esto:
var E = Elemento.prototipo; E.addEvent = function (type, fn) addEvent (this, type, fn); E.removeEvent = function (type, fn) removeEvent (this, type, fn);
Esto funcionará en todos los navegadores modernos, así como en IE8; IE7 y IE6 se ahogan Elemento
. Depende de tu audiencia; Tómelo o déjelo!
Ahora que ya sabe todo acerca de los eventos de JavaScript, no se apresure y complete su próximo proyecto con oyentes de eventos. Si tiene muchos elementos que responden al mismo tipo de evento (por ejemplo, haga clic), es mejor aprovechar el burbujeo. Simplemente puede agregar un detector de eventos a un elemento ancestral, incluso el cuerpo, y usar la propiedad target / srcElement en el objeto del evento para averiguar en qué elemento más profundo se hizo clic. Esto se llama Delegación de eventos. Aquí hay un ejemplo inútil:
Aquí hay algo de HTML:
Podemos utilizar la delegación de eventos para tratar los clics de cada uno. li
:
función de navegación (e) var el = e.target || e.srcElement; interruptor (el.id) caso 'home': alerta ('go home'); descanso; caso 'portfolio': alerta ('revisa mis productos'); descanso; caso 'sobre': alerta ('todos esos detalles desagradables'); descanso; caso "contacto": alerta ("Me halagó que quisiera hablar"); descanso; predeterminado: alerta ('¿Cómo llegaste aquí?'); var nav = document.getElementById ('nav'); addEvent (navegación, 'clic', navegación);
Usamos una declaración de cambio / caso para ver el id del elemento con un clic más profundo. Entonces, hacemos algo en consecuencia..
Así que ahora puedes manejar eventos de JavaScript con el mejor de ellos. Diviértete con él, y haz cualquier pregunta en los comentarios.!