Eventos de JavaScript desde el principio

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.!


Bienvenido a JavaScript Eventos

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.


Manejo de eventos de nivel 0

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.


Screencast completo



El objeto del evento y este

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..


Manejo de eventos de nivel 2

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);

Capturando y burbujeando

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..


Modelo de evento de Internet Explorer

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);

Momento de vuelta al burbujeo

¿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..


Algunas propiedades del objeto de evento

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.


objetivo

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;

objetivo actual

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 # wrapperoyente 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.

Otros

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!


Eventos de fijación

Hemos encontrado dos problemas principales en nuestro estudio de eventos hasta ahora.

  • IE usa un modelo diferente al de los otros navegadores.
  • IE no tiene forma de acceder al objeto principal del evento; le falta el 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!


Delegación de eventos

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:

 
  • casa
  • portafolio
  • acerca de
  • contacto

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..


Conclusión

Así que ahora puedes manejar eventos de JavaScript con el mejor de ellos. Diviértete con él, y haz cualquier pregunta en los comentarios.!