jueves, 10 de noviembre de 2011

Webkit feature: barra de desplazamiento - Actualizado 11/01/12

El problema en cuestión reside cuando se eliminan los nodos hijos de un contenedor padre a la hora de intervenir en el evento submit de un formulario, produciendo la perdida de la posición de la barra de desplazamiento.

Condiciones necesarias
  • El navegador utiliza el motor Webkit (Chrome, Safari, Konkeror, etcétera).
  • Debe de haber un formulario con un campo de texto y al mismo formulario le debe prevalecer cualquier contenido, como un texto.
  • Se llama al evento submit del formulario mediante la tecla intro (gracias esto último al campo de texto).
  • Se cancela el evento anterior mediante un listener, pero antes de ello, se eliminan los nodos hijos del contenedor padre a cambiar (removeChild), estableciendo a continuación el nuevo contenido.
  • La barra de desplazamiento debe estar visible para apreciar la anomalía.
Actualizado: Al parecer la versión del motor WebKit 535.7 a la que da soporte Chrome en su versión 16 no presenta el problema que se describe en esta entrada, así que el problema pasará a ser una mera anecdota.

Demostración con javascript nativo

http://jsfiddle.net/yeikos/muVNt/

Solución

El remedio más directo sería hacer uso de innerHTML para establecer el nuevo contenido sin eliminar los nodos hijos del contenedor a cambiar.

El problema de ello es que innerHTML no es un estándar de la W3C, ya que pertenece a Microsoft (concretamente a Internet Explorer), pero su uso se extendió a los demás navegadores.

Se prevee que en un futuro lejano esta función quede obsoleta, pero eso ya es otro cantar, ya que la alternativa sería trabajar con el DOM directamente, lo cual puede llegar a resultar muy engorroso, debiendo recurrir a diferentes frameworks, lo cual nos facilita mucho la tarea.

Otro problema es que innerHTML no evalúa las etiquetas script, por lo que si queremos hacer uso de esa funcionalidad tenemos que volver a trabajar sobre el DOM o frameworks, como jQuery.

Demostración con jQuery

jQuery también se ve afectado pero de una forma cuanto menos curiosa, ya que el contenido lo establecemos mediante la función jQuery.html, fácilmente y sin problemas, pero si éste contiene alguna etiqueta script la susodicha función cambia su forma de trabajar, utilizando la función empty para vaciar el contenido y a continuación append para añadir el contenido nuevo, y sí, como algunos estaréis pensando, la función empty de jQuery utiliza removeChild para eliminar los nodos hijos.

En este caso particular no nos vale utilizar innerHTML para establecer el nuevo contenido, ya que no evaluará las etiquetas script, así que la única solución es vaciar el contenido sin hacer uso de removeChild, es decir, asignando una cadena vacía a innerHTML o en su defecto, utilizando la función html de jQuery y pasandole como argumento una cadena vacía.

Una vez vaciado el contenido podemos establecer el contenido nuevo utilizando el DOM (jQuery.html) para que evalué las etiquetas script sin ningún tipo de problema y sin pérdida de posición de la barra de desplazamiento, ya que al encontrarse el contenido vació antes de establecer el nuevo, la función empty no tiene que vaciarlo de nuevo, ya que no hay nodos para eliminar, por lo que no hará uso de removeChild.

http://jsfiddle.net/yeikos/SgNKV


No hay comentarios:

Publicar un comentario