El modelo simple de eventos se introdujo en la versión 4 del estándar HTML y se considera parte del nivel más básico de DOM. Aunque sus características son limitadas, es el único modelo que es compatible con todos los navegadores y por tanto, el único que permite crear aplicaciones que funcionan de la misma manera en todos los navegadores.
Cada elemento XHTML tiene definida su propia lista de posibles eventos que se le pueden asignar. Un mismo tipo de evento (por ejemplo, pinchar el botón izquierdo del ratón) puede estar definido para varios elementos XHTML y un mismo elemento XHTML puede tener asociados diferentes eventos.
El nombre de los eventos se construye mediante el prefijo on
, seguido del nombre en inglés de la acción asociada al evento. Así, el evento de pinchar un elemento con el ratón se denomina onclick
y el evento asociado a la acción de mover el ratón se denomina onmousemove
.
La siguiente tabla resume los eventos más importantes definidos por JavaScript:
Evento | Descripción | Elementos para los que está definido |
---|---|---|
onblur | Deseleccionar el elemento | <button> , <input> , <label> , <select> , <textarea> , <body> |
onchange | Deseleccionar un elemento que se ha modificado | <input> , <select> , <textarea> |
onclick | Pinchar y soltar el ratón | Todos los elementos |
ondblclick | Pinchar dos veces seguidas con el ratón | Todos los elementos |
onfocus | Seleccionar un elemento | <button> , <input> , <label> , <select> , <textarea> , <body> |
onkeydown | Pulsar una tecla y no soltarla | Elementos de formulario y <body> |
onkeypress | Pulsar una tecla | Elementos de formulario y <body> |
onkeyup | Soltar una tecla pulsada | Elementos de formulario y <body> |
onload | Página cargada completamente | <body> |
onmousedown | Pulsar un botón del ratón y no soltarlo | Todos los elementos |
onmousemove | Mover el ratón | Todos los elementos |
onmouseout | El ratón "sale" del elemento | Todos los elementos |
onmouseover | El ratón "entra" en el elemento | Todos los elementos |
onmouseup | Soltar el botón del ratón | Todos los elementos |
onreset | Inicializar el formulario | <form> |
onresize | Modificar el tamaño de la ventana | <body> |
onselect | Seleccionar un texto | <input> , <textarea> |
onsubmit | Enviar el formulario | |
onunload | Se abandona la página, por ejemplo al cerrar el navegador | <body> |
Algunos de los eventos anteriores (onclick
, onkeydown
, onkeypress
, onreset
y onsubmit
) permiten evitar el comportamiento por defecto del evento si se devuelve el valor false
, tal y como se verá más adelante.
Por otra parte, las acciones típicas que realiza un usuario en una página web pueden dar lugar a una sucesión de eventos. Si se pulsa por ejemplo sobre un botón de tipo submit
se desencadenan los eventos onmousedown
, onmouseup
, onclick
y onsubmit
.
En la programación orientada a eventos, las aplicaciones esperan a que se produzcan los eventos. Una vez que se produce un evento, la aplicación responde ejecutando cierto código especialmente preparado. Este tipo de código se denomina "manejadores de eventos" (del inglés "event handlers") y las funciones externas que se definen para responder a los eventos se suelen denominar "funciones manejadoras".
En las siguientes secciones se presentan las tres formas más utilizadas para indicar el código que se ejecuta cuando se produce un evento.
La forma más sencilla de incluir un manejador de evento es mediante un atributo de XHTML. El siguiente ejemplo muestra un mensaje cuando el usuario pincha en el botón:
<input type="button" value="Pinchame y verás" onclick="alert('Gracias por pinchar');" />
Figura 6.1. Página HTML
Figura 6.2. El usuario pincha con el ratón sobre el botón que se muestra
Figura 6.3. Después de pinchar con el ratón, se muestra un mensaje en una nueva ventana
El método consiste en incluir un atributo XHTML con el mismo nombre del evento que se quiere procesar. En este caso, como se quiere mostrar un mensaje cuando se pincha con el ratón sobre un botón, el evento es onclick
.
El contenido del atributo es una cadena de texto que contiene todas las instrucciones JavaScript que se ejecutan cuando se produce el evento. En este caso, el código JavaScript es muy sencillo, ya que solamente se trata de mostrar un mensaje mediante la función alert()
.
En este otro ejemplo, se muestra un mensaje cuando la página se ha cargado completamente:
<body onload="alert('La página se ha cargado completamente');"> ... </body>
El evento onload
es uno de los más utilizados porque, como se vio en el capítulo de DOM, las funciones de acceso y manipulación de los nodos del árbol DOM solamente están disponibles cuando la página se carga por completo.
En los eventos de JavaScript, se puede utilizar la palabra reservada this
para referirse al elemento XHTML sobre el que se está ejecutando el evento. Esta técnica es útil para ejemplos como el siguiente, en el que se modifican las propiedades del elemento que provoca el evento.
En el siguiente ejemplo, se muestra un borde destacado en el elemento <div>
cuando el usuario pasa el ratón por encima. Cuando el ratón sale del <div>
, se vuelve a mostrar el borde original:
<div id="elemento" style="padding: .2em; width: 150px; height: 60px; border: thin solid silver" onmouseover = "document.getElementById('elemento').style.borderColor = 'black'" onmouseout = "document.getElementById('elemento').style.borderColor = 'silver'"> Sección de contenidos... </div>
El evento onmouseover
se activa cuando el ratón pasa por encima del elemento, en este caso el <div>
. Para cambiar el color del borde, se utiliza la propiedad border-color
de CSS. Por lo tanto, en primer lugar se obtiene la referencia del elemento mediante document.getElementById('elemento')
. A continuación, se utiliza la propiedad style
para acceder a las propiedades CSS y se modifica el nombre de border-color
por el de borderColor
. Para volver al color original cuando el ratón sale del elemento, se realiza la misma operación sobre el evento onmouseout
.
El uso de la variable this
puede simplificar todos estos pasos, ya que dentro de un manejador de eventos, la variable this
equivale al elemento que ha provocado el evento. Así, la variable this
es igual al <div>
de la página y por tanto this.style.borderColor
permite cambiar de forma directa el color del borde del <div>
:
<div style="padding: .2em; width: 150px; height: 60px; border: thin solid silver" onmouseover="this.style.borderColor='black'" onmouseout="this.style.borderColor='silver'"> Sección de contenidos... </div>
Haciendo uso de la variable this
, el código es mucho más sencillo de escribir, leer y mantener.
La definición de manejadores de eventos en los atributos XHTML es un método sencillo pero poco aconsejable para tratar con los eventos en JavaScript. El principal inconveniente es que se complica en exceso en cuanto se añaden algunas pocas instrucciones, por lo que solamente es recomendable para los casos más sencillos.
Cuando el código de la función manejadora es más complejo, como por ejemplo la validación de un formulario, es aconsejable agrupar todo el código JavaScript en una función externa que se invoca desde el código XHTML cuando se produce el evento.
De esta forma, el siguiente ejemplo:
<input type="button" value="Pinchame y verás" onclick="alert('Gracias por pinchar');" />
Se puede transformar en:
function muestraMensaje() { alert('Gracias por pinchar'); } <input type="button" value="Pinchame y verás" onclick="muestraMensaje()" />
En las funciones externas no es posible utilizar la variable this
de la misma forma que en los manejadores insertados en los atributos XHTML. Por tanto, es necesario pasar la variable this
como parámetro a la función manejadora:
function resalta(elemento) { switch(elemento.style.borderColor) { case 'silver': case 'silver silver silver silver': case '#c0c0c0': elemento.style.borderColor = 'black'; break; case 'black': case 'black black black black': case '#000000': elemento.style.borderColor = 'silver'; break; } } <div style="padding: .2em; width: 150px; height: 60px; border: thin solid silver" onmouseover="resalta(this)" onmouseout="resalta(this)"> Sección de contenidos... </div>
En el ejemplo anterior, a la función externa se le pasa el parámetro this
, que dentro de la función se denomina elemento
. Al pasar this
como parámetro, es posible acceder de forma directa desde la función externa a las propiedades del elemento que ha provocado el evento.
Por otra parte, el ejemplo anterior se complica por la forma en la que los distintos navegadores almacenan el valor de la propiedad borderColor
. Mientras que Firefox almacena (en caso de que los cuatro bordes coincidan en color) el valor simple black
, Internet Explorer lo almacena como black black black black
y Opera almacena su representación hexadecimal #000000
.
Utilizar los atributos XHTML o las funciones externas para añadir manejadores de eventos tiene un grave inconveniente: "ensucian" el código XHTML de la página.
Como es conocido, al crear páginas web se recomienda separar los contenidos (XHTML) de la presentación (CSS). En lo posible, también se recomienda separar los contenidos (XHTML) de la programación (JavaScript). Mezclar JavaScript y XHTML complica excesivamente el código fuente de la página, dificulta su mantenimiento y reduce la semántica del documento final producido.
Afortunadamente, existe un método alternativo para definir los manejadores de eventos de JavaScript. Esta técnica consiste en asignar las funciones externas mediante las propiedades DOM de los elementos XHTML. Así, el siguiente ejemplo:
<input id="pinchable" type="button" value="Pinchame y verás" onclick="alert('Gracias por pinchar');" />
Se puede transformar en:
function muestraMensaje() { alert('Gracias por pinchar'); } document.getElementById("pinchable").onclick = muestraMensaje; <input id="pinchable" type="button" value="Pinchame y verás" />
El código XHTML resultante es muy "limpio", ya que no se mezcla con el código JavaScript. La técnica de los manejadores semánticos consiste en:
id
. Otra ventaja adicional de esta técnica es que las funciones externas pueden utilizar la variable this
referida al elemento que original el evento.
Asignar la función manejadora mediante DOM es un proceso que requiere una explicación detallada. En primer lugar, se obtiene la referencia del elemento al que se va a asignar el manejador:
document.getElementById("pinchable");
A continuación, se asigna la función externa al evento deseado mediante una propiedad del elemento con el mismo nombre del evento:
document.getElementById("pinchable").onclick = ...
Por último, se asigna la función externa. Como ya se ha comentado en capítulos anteriores, lo más importante (y la causa más común de errores) es indicar solamente el nombre de la función, es decir, prescindir de los paréntesis al asignar la función:
document.getElementById("pinchable").onclick = muestraMensaje;
Si se añaden los paréntesis al final, en realidad se está invocando la función y asignando el valor devuelto por la función al evento onclick
de elemento.
El único inconveniente de este método es que los manejadores se asignan mediante las funciones DOM, que solamente se pueden utilizar después de que la página se ha cargado completamente. De esta forma, para que la asignación de los manejadores no resulte errónea, es necesario asegurarse de que la página ya se ha cargado.
Una de las formas más sencillas de asegurar que cierto código se va a ejecutar después de que la página se cargue por completo es utilizar el evento onload
:
window.onload = function() { document.getElementById("pinchable").onclick = muestraMensaje; }
La técnica anterior utiliza una función anónima para asignar algunas instrucciones al evento onload
de la página (en este caso se ha establecido mediante el objeto window
). De esta forma, para asegurar que cierto código se va a ejecutar después de que la página se haya cargado, sólo es necesario incluirlo en el interior de la siguiente construcción:
window.onload = function() { ... }
Ejercicio 10
A partir de la página web proporcionada y utilizando manejadores de eventos semánticos, completar el código JavaScript para que:
Cuando la sección se oculte, debe cambiar el mensaje del enlace asociado (pista: propiedad innerHTML
).