En el post pasado, hablé de que Google está invitando a los desarrolladores a detectar navegadores basados en Chrome para aprovechar las novedades que ellos están implementando en Javascript, con la justificación de que «para que todos los navegadores soporten esas novedades tendrá que pasar mucho tiempo».
Visto de esta forma, estamos cayendo en lo mismo que sucedía en tiempos de IE vs Netscape: darle preferencia a un navegador y discriminar al resto. Es verdad que hay diferencias entre navegadores, pero la misma forma de Javascript nos permite sortear esas diferencias en la mayoría de los casos.
Un primer caso que puede presentarse es cuando algún navegador realiza una misma operación de forma distinta a otro. En este artículo hablaré de cómo detectar esas diferencias.
Un ejemplo muy sencillo es la asignación de eventos. Los eventos, como sabemos, son aquellas operaciones que se ejecutan por alguna actividad del usuario en la página, que puede ir desde pasar el cursor encima de la página, hasta dar clic a un elemento, o presionar una tecla.
En html, los eventos se pueden asignar desde un atributo:
<body onload="body_load()"> <form onsubmit="form_submit()"> <input type="submit" onclick="button_click()"/> </form> </body> <script> function body_load(){ } function form_submit(){ } function button_click(){ } </script>
Cuando usamos los atributos on[evento]
, automáticamente le estamos asignando la función que se ejecutará al evento disparado por el usuario (en este caso, carga de la página, envío del formulario y clic en el botón, respectivamente).
Incluso, podemos enviar un parámetro con información del evento, el cual puede ser trabajado por la función según el evento que corresponda:
<input type="submit" onclick="button_click(event)"/>
Aquí se presenta la situación de la que hablo en este tema: algunos navegadores consideran el parámetro event
como no definido (undefined
), ya que en ningún momento estoy definiendo esa variable, ni le estoy asignando un valor. En estos navegadores podemos recurrir a un objeto que sí contiene la información requerida:
function button_click(e){ // e recibe el parámetro event if (e === undefined) e = window.event; }
Hecho esto, podemos usar la variable e
como la necesitemos, por ejemplo, para prevenir el comportamiento predeterminado del botón, que en este caso es enviar los datos del formulario. Aquí se presenta otro caso de detección de funciones en el navegador, pues hay distintas formas de cancelar un evento en los diferentes navegadores. Aquí podemos hacer algo así:
function button_click(e){ // e recibe el parámetro event if (e === undefined) e = window.event; if (e !== undefined){ // se puede asumir que e siempre traerá un // valor en este punto del código, pero por // si las dudas, evitamos una excepción. if (e.preventDefault !== undefined) { e.preventDefault(); } else if (e.returnValue !== undefined) { e.returnValue = false; } else if (e.cancelBubble !== undefined) { e.cancelBubble = true; } } }
¿Qué estamos haciendo? Estamos realizando una misma acción con tres distintas opciones. La primera, la función preventDefault
, es usada por algunos programas. Para saber si el navegador la soporta, verificamos que esté definida (nótese que omitimos los paréntesis de la función en la comparación, para que no la ejecute y la considere como «variable») y de ser así, la ejecuta. Si no está definida, entonces recurrimos a una segunda opción, que es la variable returnValue
. Si le damos valor false
a esta variable, se cancela el evento. Si la variable no existe, buscamos la variable cancelBubble
, que es usada por Internet Explorer, y le damos un valor true
para cancelar el evento.
Ésta es la forma correcta de ejecutar funciones en Javascript, cuando sabemos que cada navegador puede hacer las cosas de modo distinto. Siempre nuestro codigo debe «averiguar» si la función o variable existe antes de utilizarla.
function AgregarTexto(elemento, texto){ if (elemento.textContent !== undefined) { elemento.textContent = texto; } else if (elemento.innerText !== undefined) { elemento.innerText = texto; } else { var t = document.createTextNode(t); var children = (element.children !== undefined ? element.children : element.childNodes); if (children.length > 0) { element.replaceChild(t, children[0]); } else { element.appendChild(t); } } }
Claro que esto puede ser mucho trabajo para un programador. Es por eso que frameworks como jQuery nos ahorran mucho de este trabajo, dándonos una función para cada una de estas operaciones, la cual incluye internamente todo el código que tendríamos que hacer a mano. Por ejemplo:
// Función a ejecutar al cargarse la página $(document).ready(function() { // Función a ejecutar al dar clic a un botón $('#boton').click(function(e) { // El objeto e es definido por jQuery Incluye una función propia para cancelar el evento. e.preventDefault() AgregarTexto($('#elemento'), "nuevo texto"); }); }); function AgregarTexto(elemento, texto){ // Reduzco la función AgregarTexto a una sola línea $(elemento).text(texto); }
Cada función de jQuery (ready
, click
, preventDefault
, text
) internamente incluye todas las validaciones y operaciones para funcionar en cualquier navegador.
Es verdad que las tecnologías web están avanzando muy rápido, y desgraciadamente hay navegadores que se están quedando atrás, y el decidirnos por un solo navegador suena muy atractivo para nosotros como programadores. Pero como desarrolladores web, la regla es soportar a todos los navegadores posibles. Si no estamos dispuestos a eso, mejor nos dedicamos a otra cosa.
Un comentario sobre “Javascript – Detección de soporte de funciones”