El Modelo de Eventos del DOM
Revisa la recomendación oficial W3C DOM2 Event standard .Escuchadores de Eventos ('Event Listeners')
Los objetos DOM también pueden ser registrados como escuchadores de eventos. Esta característica puede ser utilizada para asignar multiples manejadores ('handlers') para un evento dado. Ésto te permite, además, capturar eventos durante cualquiera de las dos fases en el flujo de eventos ('event flow'), captura ('capture') o burbujeo ('bubble').
La diferencia entre estas dos fases será cubierta más tarde en la discusión sobre el flujo de eventos. Pero, por ahora, veamos cómo registrar un escuchador de eventos.
Los métodos básicos y su sintáxis son
node.addEventListener(eventType, function, useCapture);
node.removeEventListener(eventType, function, useCapture);
donde eventType es un nombre predefinido de evento
como "mouseover" o "click" (el mismo que el correspondiente a un attributo
evento pero sin el prefijo "on"), function es el nombre
de la función manejador y useCapture es un boleano
que especifica en qué fase del flujo de eventos el manejador debe
ser llamado.
Para demostrarlo, en el ejemplo previo, podríamos haber asignado manejadores de eventos para el elemento párrafo del ejemplo con el siguiente código:
var el = document.getElementById('sample1');
el.addEventListener("mouseover", highlight, false);
el.addEventListener("mouseout", normal, false);
También podrían ser asignados manejadores adicionales para un evento dado:
el.addEventListener("mouseover", highlight2, true);
el.addEventListener("mouseover", highlight3, false);
Cada escuchador de eventos podrá ser eliminado posteriormente especificando los mismos argumentos:
el.removeEventListener("mouseover", highlight2, true);
el.removeEventListener("mouseover", highlight3, false);
Fíjate que debes especificar el mismo valor de useCapture
cuando eleimines un escuchador que cuando lo añades. Ésto
se debe a que,
el.addEventListener("mouseover", highlight, true);
el.addEventListener("mouseover", highlight, false);
definen dos escuchadore de eventos distintos, que llaman a la misma función para el mismo evento en el mismo elemento pero que se activan durante fases diferentes.
Una ventaja de este método es es que los escuchadores de eventos pueden ser asignados a cualquier nodo, incluso a los nodos de texto, a los que no se podía asignar manejadores de eventos, ya que no tenían atributos.
Internet Explorer, hasta la version 6, y Opera, hasta la version 5, no
soportan los escuchadores de eventos. IE proporciona los métodos
attachEvent() y detachEvent que te ofrecen la posibilidad
de asignar multiples manejadores para un evento dado (observa que estos métodos
esperan el prefijo "on" en el nombre del evento) y eliminarlos posteriormente:
var el = document.getElementById('sample1');
el.attachEvent("onmouseover", highlight);
el.attachEvent("onmouseover", highlight2);
el.attachEvent("onmouseover", highlight3);
el.attachEvent("onmouseout", normal);
...
el.detachEvent("onmouseover", highlight2);
el.detachEvent("onmouseover", highlight3);
De cualquier modo, esta característica no permite especificar la fase del evento, no puede ser utilizada en nodos de texto y no es parte del estándar del DOM.
Flujo de Eventos
Antes de entrar en el procesamiento de eventos, es de gran ayuda comprender el flujo de eventos en el DOM. Los documentos HTML (y XML en general) son de naturaleza jerárquica. Los Elementos y el texto están jerarquizados dentro de otros elementos. Por esto, cuando un evento ocurre en un objeto en particular, dicho evento está ocurriendo en cualquier objeto(s) que contenga(n) a dicho objeto.
Para ilustrar esto, consideremos el siguiente código HTML:
<div>
<p>Algún texto en un elemento párrafo.</p>
<p>Otro elemento párrafo con texto.</p>
<p>Y otro párrafo con texto y además un
<a href="blank.html">link</a>.</p>
</div>
Si haces click en el link definido en este ejemplo de código, se
disparará un evento onclick en la etiqueta A.
Pero también estás haciendo click en el párrafo que
contiene dicho link, y el elemento DIV que contiene dicho elemento P, y
así, siguiendo hacia arriba hasta el mismo objeto document
.
Cualquiera de los elementos en esta cadena puede tener un manejador de
eventos asignado para capturar el evento onclick, independientemente
de cuál fué el elemento que lo originó.
Burbujeo de Eventos
El modelo de eventos del DOM proporciona con este fin un concepto llamado
burbujeo de eventos ('event bubbling'). Por ejemplo, supongamos que
un manejador del evento onclick ha sido asignado a la etiqueta
DIV anterior. Haciendo click en el link dispararíamos el evento primero
en el elemento A, dicho evento "burbujearía" hacia arriba hasta el
elemento P que lo contiene y seguiría hacia arriba hasta el elemento
DIV donde la función manejadora del evento sería llamada.
Es posible para el manejador cancelar el evento, pero asumiendo que no va a evitar que el evento continúe burbujeando hacia arriba hasta la raíz del documento y que, finalmente, el navegador seguiría la acción por defecto de cargar la URL del enlace en la ventana.
Fíjate en que el elemento P podría tener fijado, además,
un manejador del evento onclick , como podría cualquier
elemento anterior al elemento DIV en el árbol del documento. Todos
estos manejadores podrían ser sucesivamente llamados conforme
el evento burbujea hacia arriba hasta la raíz del documento.
Ésto se conoce como la fase de burbujeo ('bubble') en el
modelo de eventos del DOM. No todos los eventos burbujean, por ejemplo
onfocus y onblur no lo hacen. De la misma forma, no
todos los burbujeos de eventos pueden ser cancelados, deteniendo la propagación.
Puedes determinar qué eventos burbujean y cuáles pueden ser
cancelados respectivamente echándole un vistazo a la documentación
para el evento o, como vamos a ver, usando el objeto Event.