Webs de contenido dinámico
Categorías : JavaScript, JQuery, PHP, HTML, Programación.

Desde que se empezó a usar Ajax se podría decir que empezaron a existir webs con contenido dinámico, al principio se utilizaba para cosas simples, y estaba pensado mas bien como una herramienta para consultar pequeñas cantidades de datos. Con el paso de los años Ajax se ha vuelto prácticamente imprescindible en cualquier proyecto web medio/grande.
Por poner un ejemplo claro, Facebook carga prácticamente todo su contenido mediante Ajax, seguro que todos conocéis su scroll infinito.
También se pueden encontrar paginas tipo blog/revistas que hacen uso del scroll infinito, y que además son capaces de modificar su URL sin tener que re-cargar toda la web.
A mí personalmente el tema del scroll infinito no me hace mucha gracia, pero sí que me gusta mucho la idea de tener una web eficiente, y que sea capaz de entregar los datos justos al usuario, además de darle una buena experiencia en la navegación.
En este tutorial os voy mostrar cómo hacer una web muy simple con un menú estático, que pueda cargar todos los documentos de forma dinámica en un marco. Antes de nada me gustaría que vieras un poco como he dividido los datos de mi web, ya que tenéis que tener muy claro que partes son esenciales y que partes no. Tal y como veis mi web ahora mismo, se podría dividir en 2 partes :
- La plantilla que contiene la maquetación, los menús, las cabeceras css y js, las fuentes, etc...
- El documento que contiene la información que ha solicitado el usuario.
En una web normal (estática), el servidor nos mandará cada vez que abramos un enlace tanto la plantilla como el documento. Pero que es lo que pasa si navegamos entre 50 documentos de la misma web? pues que el servidor nos manda 50 veces la plantilla junto al documento, y considerando que la plantilla es siempre la misma, aquí estamos derrochando el ancho de banda tanto del servidor como del usuario.
En una web dinámica se evita ese derroche de ancho de banda, ya que si el usuario entra en 50 urls durante la misma sesión, recibirá la plantilla en la primera petición y luego recibirá los 50 documentos. Por lo que nos ahorramos los datos de un total de 49 plantillas respecto al modelo estático.
Lo que vamos a hacer en este tutorial será crear una web muy sencilla con un menú que nos dejara navegar por 6 documentos. Lo que nos permitirá ver cómo trabajar con Ajax y como debemos gestionar el historial de documentos de la pestaña (para modificar la url).
Creación de la plantilla
Lo primero que necesitamos es la plantilla básica para nuestros documentos. La idea principal es que la plantilla se mande una sola vez al principio, y que luego si el usuario carga mas documentos solo reciba los datos de ellos pero sin mandar otra vez la plantilla.
La forma mas fácil de hacernos una plantilla es crear un php con una función
// Función para iniciar la plantilla (requiere el nombre del archivo, y el titulo del documento)function IniciarPlantilla($Archivo, $Titulo) {// Si no existe el parámetro SinPlantilla es porque se está cargando la web por primera vezif (!isset($_POST["SinPlantilla"])) {echo "<!DOCTYPE HTML>"."<html lang='es'>"."<head>"."<title>".$Titulo."</title>". // Titulo"<meta http-equiv='Content-Type' content='text/html; charset=utf-8' />". // Codificación UTF8"<link rel='stylesheet' href='TutoWebDinamica.css'>". // Archivo con el CSS para la web"<script src='//ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js'></script>". // jQuery"<script src='TutoWebDinamica.js'></script>". // Archivo con el JS para la web"</head>".// El body empieza con el atributo cargando (para la animación de carga entre documentos)"<body cargando='true'>".// Menu superior fijo para navegar por los enlaces"<div id='MenuSuperior'>"./* El atributo archivo se utiliza para saber en que documento estamosy de esta forma poder resaltar el botón del documento actual (todo mediante css) */"<ul archivo='".$Archivo."'>"."<li><a href='Amarillo.php'>Amarillo</a></li>"."<li><a href='Azul.php'>Azul</a></li>"."<li><a href='Verde.php'>Verde</a></li>"."<li><a href='Rojo.php'>Rojo</a></li>"."<li><a href='Blanco.php'>Blanco</a></li>"."<li><a href='Negro.php'>Negro</a></li>"."</ul>"."</div>".// Marco donde se cargaran los documentos dinámicos mediante JavaScript"<div id='MarcoDinamico'>";}// Datos del archivo que esta usando la plantilla (siempre quedan al principio del MarcoDinamico)echo "<div id='InformacionDinamica' archivo='".$Archivo."' titulo='".$Titulo."'></div>";}
La función SinPlantilla
en el POST. Luego en el código de la web vamos a tener que re-direccionar todos los enlaces que apunten a nuestro servidor para hacer un POST con la variable SinPLantilla, para que de esta forma nos devuelva solo el documento sin la plantilla.
Otra cosa a remarcar es la
// Función para terminar la plantillafunction TerminarPlantilla() {if (!isset($_POST["SinPlantilla"])) {echo "</div>". // Final del MarcoDinamico"</body>"."</html>";}}
La función
JavaScript
Ahora que ya tenemos la plantilla, vamos a por el código en java script. Necesitaremos lo siguiente :
- Hacer una función para cargar enlaces dinámicos en el div #MarcoDinamico
- Controlar el historial de la pestaña, detectando cuando el usuario pulsa hacia atrás o hacia adelante.
- Re-direccionar todas las etiquetas
a href
a la función para cargar enlaces dinámicos.
Función para cargar enlaces dinámicos
Antes de nada debo remarcar que al cargar dinámicamente el documento, el navegador seguirá con la primera URL, y vamos a tener que decirle la nueva URL manualmente. Para ello vamos a tener que toquetear el historial de la pestaña.
Para tener acceso al historial de la pestaña tenemos el objeto window.history, del cual solo vamos a utilizar la función pushState. Echad un vistazo a la función
// Función que carga una URL dinámicamentefunction CargarURL(URL) {// Si hay una petición ajax pendiente, la cancelamosif (PeticionAjax != 0) PeticionAjax.abort();// Inicio la animación de la carga$("body").attr({ "cargando" : true });console.log("CargarURL", URL, document.title);// Petición ajax para obtener el documento dinámicoPeticionAjax = $.post(URL, { "SinPlantilla" : "true" }).done(function(data) {// Asigno el nuevo HTML para el marco dinámico$("#MarcoDinamico").html(data);// Re-direcciono todas las etiquetas 'a' a la funcion CargarURL, y actualizo el titulo y el menú.ActualizarContenido();// Añado la nueva URL al historial de la pestaña, y esta queda como la URL actual.window.history.pushState(null, document.title, URL);// Borramos la petición ajax de la memóriaPeticionAjax = 0;// Error en la petición ajax}).fail(function(jqXHR, textStatus, tError) {// Termino la animación de la carga$("body").removeAttr("cargando");// Si hay un erroralert("Error cargando " + URL);// Borramos la petición ajax de la memóriaPeticionAjax = 0;});}
Para empezar en la body
. De esta forma se iniciara una pequeña animación.
En la
Lo mas destacable de la función es la
CallBack del historial
Para poder controlar cuando el usuario va hacia atrás o hacia adelante en el historial, y de esta forma pasarle solo el documento sin la plantilla, debemos sobre-escribir el callback del historial.
/* CALLBACK para el historial */window.addEventListener('popstate', function(event) {// Si hay una petición ajax pendiente, la cancelamosif (PeticionAjax != 0) PeticionAjax.abort();// Inicio la animación de la carga$("body").attr({ "cargando" : true });console.log("CALLBACK_Histroial", window.location.href, event);// Petición ajax para obtener el documento dinámicoPeticionAjax = $.post(window.location.href, { "SinPlantilla" : "true" }).done(function(data) {// Asigno el nuevo HTML para el marco dinámico$("#MarcoDinamico").html(data);// Re-direcciono todas las etiquetas 'a' a la funcion CargarURL, y actualizo el titulo y el menú.ActualizarContenido();// Borramos la petición ajax de la memóriaPeticionAjax = 0;// Error en la petición ajax}).fail(function(jqXHR, textStatus, tError) {// Termino la animación de la carga$("body").removeAttr("cargando");// Si hay un erroralert("Error cargando " + window.location.href);// Borramos la petición ajax de la memóriaPeticionAjax = 0;});}, false);
En esencia es prácticamente el mismo código de la función window.history.pushState
, ya que estamos navegando por el historial y no es una nueva entrada.
Hay que remarcar que en la
Sobretodo hay que asignar a la variable
window.location.href
contiene la nueva URL.Re-direccionar etiquetas a href
Necesitamos capturar todos los eventos OnClick de los enlaces de la página, para evitar que el navegador salte a dicho enlace, y para que podamos cargarlo utilizando la función CargarURL
.
Es muy importante mantener las etiquetas a para los buscadores, y a la vez poder utilizarlas para cargar contenido dinámico de nuestra web.
Vamos a crear una función para enlazar los eventos OnClick, y ya de paso también para actualizar el título de la página y el botón del menú seleccionado.
// Esta función re-emplaza el evento click de las etiquetas "a" para cargar el enlace dinamicamente.function ActualizarContenido() {// Solo se redireccionan etiquetas sin el atributo target$("a[href]:not([target])").off("click").on("click", function(e) {// Evito que el evento llegue a la función OnClick por defecto de los enlacese.preventDefault();// Cargo la URL del enlace utilizando AjaxCargarURL($(this).attr("href"));// Devuelvo false para que el evento no se extienda a sus padres.return false;});/* El titulo y el nombre del archivo los podemos encontrar en el div #InformacionDinamicaque se ha creado expresamente en la plantilla para esta finalidad. */// Asigno el nuevo titulodocument.title = $("#InformacionDinamica").attr("titulo");// Asigno el boton actual del menú superior$("#MenuSuperior > ul").attr({ "archivo" : $("#InformacionDinamica").attr("archivo") });// Termino la animación de la carga$("body").removeAttr("cargando");}
En la target
establecido. Lo que tenemos que tener en cuenta, es que los enlaces que apunten a ventanas/pestañas nuevas deberán ser aquellos que apunten fuera de nuestro servidor. Para los enlaces que apunten a nuestro servidor usaremos la etiqueta a sin el atributo target
En la div
ul
que contiene el menú
Por ultimo en la body
, lo que finalizará la animación de la carga. La animación a decir verdad es una chorrada, y prácticamente es imperceptible ya que el ejemplo tiene muy poco contenido, lo que hace que el tiempo de carga sea mínimo. De todas formas si os habéis fijado en la animación de carga de devildrey33, os puedo decir que funciona de un modo muy similar.
Y esto es todo por hoy, como siempre podéis ver el ejemplo o descargarlo. Un saludo!