Scripts DOM para todos los navegadores: Manejadores de eventos
By Scott Andrew LePera
February 12, 2001
Traducción al español de Jose Luis Pumarega y Fernando Gutierrez.
Es posible que hayas pensado que, con la aparición de Netscape 6 y el creciente soporte de los estandares de Internet Explorer 5, la programación de scripts multinavegador pertenece al pasado. Prueba de nuevo. Existen aún numerosas diferencias entre ambos navegadores. La buena noticia es que, en lugar de compensar las debilidades de Netscape, jugaremos con sus fortalezas y codificaremos evitando las implementaciones propietarias de IE. No se interprete esto como un golpe a Microsoft, que ha añadido algunas características bastante útiles a su navegador. Pero el reto no es confiarse a código propietario, sino hacer cuanto esté en nuestra mano por utilizar las recomendaciones del W3C para el Document Object Model y su interfaz ECMAScript, y sólo duplicar el código cuando sea necesario.
Las diferencias en el registro de eventos en NS6 e IE5 son un perfecto ejemplo. Tal como vimos en Trabajando con Eventos en Netscape 6, NS6 implementa la interfaz EventListener según se describe en la especificación del W3C. Para añadir un evento a un elemento, utilizas el método addEventListener del elemento para definir el tipo de evento que quieres detectar, la función a ejecutar cuando el evento sea activado, así como lo que quieras usar para la captura del evento:
object.addEventListener(String evType, Function fn, Boolean useCapture);
Para ilustrarlo, así es como puedes adjuntar un manejador de evento onmousedown llamado processEvent a un objeto de imagen en NS6:
imgObj.addEventListener("mousedown", processEvent, false);
Para eliminar el manejador, sencillamente llamas al método removeEventListener del elemento utilizando los mismos parámetros:
imgObj.removeEventListener("mousedown", processEvent, false);
IE5 no utiliza la interfaz EventListener. Sin embargo, tiene un conjunto similar de métodos, attachEvent y detachEvent, que toman parámetros similares. Así añadiríamos el mismo evento al mismo objeto en IE:
imgObj.attachEvent("onmousedown", processEvent);
Inmediatamente advertimos dos cosas:
- el tipo de evento debe incluir "on" al inicio de la cadena, y
- se omite el booleano useCapture, opción por defecto en IE
Microsoft implementó tempranamente varios de los documentos de trabajo y recomendaciones del W3C, así que es posible que attachEvent fuese un intento de implementar la interfaz EventLister antes de su definitiva formalización.
Con esta información, no es dificil ver cómo podremos obviar estas diferencias con un poco de creatividad en nuestros scripts. ¡Construyamos nuestra propia interfaz!
Comenzaremos creando una función que sustituya la implementación de IE5 y NS6. La llamaremos addEvent y la diseñaremos para admitir cuatro parámetros:
- el objeto al que añadiremos el manejador de evento
- y los tres parámetros requeridos por la interfaz EventListener, descrita anteriormente
function addEvent(obj, evType, fn, useCapture){
}
Ahora, en lugar de empezar con la detección de navegador, comprobaremos en primer lugar, si el objeto implementa la interfaz EventListener. Si es así, sencillamente la utilizaremos y la llamaremos algún día. Esto mantendrá la compatibilidad de nuestro código si IE implementa la misma interfaz en el futuro.
function addEvent(obj, evType, fn, useCapture){
if (obj.addEventListener){
obj.addEventListener(evType,fn,useCapture);
return true;
}
}
La sentencia "return true;" es sencillamente para devolver un valor de vuelta en el caso de NS6. addEventListener no devuelve un valor por sí mismo, pero el attachEvent de IE sí devuelve verdadero o falso en función de si la operación tiene éxito.
Si addEventListener no está presente, asumiremos IE5 y comprobaremos en su lugar attachEvent.
function addEvent(obj, evType, fn, useCapture){
if (obj.addEventListener){
obj.addEventListener(evType, fn, useCapture);
return true;
} else if (obj.attachEvent){
var r = obj.attachEvent("on"+evType, fn);
return r;
} else {
alert("Handler could not be attached");
}
}
Fíjate que añado "on" antes de evType, y descarto el booleano useCapture, que es relevante, únicamente en la interfaz EventListener. Si el navegador no implementa ni addEventListener ni attachEvent, el método alert avisa al desarrollador del problema.
Para quitar un evento, podemos construir fácilmente un método removeEvent que utilice casi exactamente el mismo código, pero utilizando removeEventListener y detachEvent.
function removeEvent(obj, evType, fn, useCapture){
if (obj.removeEventListener){
obj.removeEventListener(evType, fn, useCapture);
return true;
} else if (obj.detachEvent){
var r = obj.detachEvent("on"+evType, fn);
return r;
} else {
alert("Handler could not be removed");
}
}
En sólo unas cuantas líneas de código, hemos tendido un puente entre los modelos de eventos de IE5 y NS6. Este código puede ampliarse para incluir mayor detección de errores, o si eres realmente ambicioso, compatibilidad hacia atrás con NS4/IE4. (Tu mismo.)
A medida que se incremente el soporte de los estandares, workarounds como este llegarán a ser, esperemos, innecesarios. Por ello debemos esforzarnos en usar, en nuestras aplicaciones web, soluciones basadas en los estandares y animar a los fabricantes de navegadores a implementar los estandares antes que características propietarias.
- Comenta este tutorial.
- Encuentra más acerca de Netscape 6.0 en developer.netscape.com
- Aprende sobre DOM, CSS y soporte standard www.w3c.org
- Únete a la causa del Web Standards Project www.webstandards.org
Copyright© 2001 by Scott Andrew LePera.