13 KiB
Plantillas HTML y rutas en una aplicación web
Pre-lecture prueba
Introducción
Desde la llegada de JavaScript a los navegadores, los sitios web se están volviendo más interactivos y complejos que nunca. Las tecnologías web ahora se utilizan comúnmente para crear aplicaciones completamente funcionales que se ejecutan directamente en un navegador que llamamos aplicaciones web. Como las aplicaciones web son muy interactivas, los usuarios no quieren esperar a que se vuelva a cargar la página completa cada vez que se realiza una acción. Es por eso que JavaScript se usa para actualizar el HTML directamente usando el DOM, para brindar una experiencia de usuario más fluida.
En esta lección, vamos a sentar las bases para crear una aplicación web bancaria, utilizando plantillas HTML para crear múltiples pantallas que se pueden mostrar y actualizar sin tener que volver a cargar toda la página HTML.
Requisito previo
Necesita un servidor web local para probar la aplicación web que crearemos en esta lección. Si no tiene uno, puede instalar Node.js y usar el comando npx lite-server
de la carpeta de su proyecto. Creará un servidor web local y abrirá su aplicación en un navegador.
Preparación
En su computadora, cree una carpeta llamada bank
con un archivo llamado index.html
dentro. Comenzaremos desde este HTML boilerplate:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Bank App</title>
</head>
<body>
<!-- Aquí es donde trabajarás -->
</body>
</html>
Plantillas HTML
Si desea crear varias pantallas para una página web, una solución sería crear un archivo HTML para cada pantalla que desee mostrar. Sin embargo, esta solución tiene algunos inconvenientes:
- Tienes que volver a cargar todo el HTML al cambiar de pantalla, lo que puede ser lento.
- Es difícil compartir datos entre las diferentes pantallas.
Otro enfoque es tener un solo archivo HTML y definir múltiples plantillas HTML usando el elemento <template>
. Una plantilla es un bloque HTML reutilizable que el navegador no muestra y debe instanciarse en tiempo de ejecución mediante JavaScript.
Tarea:
Crearemos una aplicación bancaria con dos pantallas: la página de inicio de sesión y el panel de control. Primero, agreguemos en el cuerpo HTML un elemento de marcador de posición que usaremos para instanciar las diferentes pantallas de nuestra aplicación:
<div id="app">Loading...</div>
Le daremos un id
para que sea más fácil localizarlo con JavaScript más adelante.
Consejo: dado que el contenido de este elemento será reemplazado, podemos poner un mensaje de carga o un indicador que se mostrará mientras se carga la aplicación.
A continuación, agreguemos debajo la plantilla HTML para la página de inicio de sesión. Por ahora, solo pondremos allí un título y una sección que contiene un botón que usaremos para realizar la navegación.
<template id="login">
<h1>Bank App</h1>
<section>
<button>Login</button>
</section>
</template>
Luego agregaremos otra plantilla HTML para la página del tablero. Esta página contendrá diferentes secciones:
- Un encabezado con un título y un botón para cerrar sesión
- El saldo actual de la cuenta bancaria
- Una lista de transacciones, que se muestra en una tabla.
<template id="dashboard">
<header>
<h1>Bank App</h1>
<button>Logout</button>
</header>
<section>
Balance: 100$
</section>
<section>
<h2>Transactions</h2>
<table>
<thead>
<tr>
<th>Date</th>
<th>Object</th>
<th>Amount</th>
</tr>
</thead>
<tbody></tbody>
</table>
</section>
</template>
Sugerencia: al crear plantillas HTML, si desea ver cómo se verá, puede comentar las líneas <template>
y </template>
encerrándolas entre <!-- -->
.
✅ ¿Por qué crees que usamos atributos ʻid` en las plantillas? ¿Podríamos usar algo más como clases?
Visualización de plantillas con JavaScript
Si prueba su archivo HTML actual en un navegador, verá que se atasca mostrando Loading...
. Eso es porque necesitamos agregar código JavaScript para crear instancias y mostrar las plantillas HTML.
La instanciación de una plantilla se suele realizar en 3 pasos:
- Recupere el elemento de plantilla en el DOM, por ejemplo, usando
document.getElementById
. - Clone el elemento de plantilla, usando
cloneNode
. - Adjúntelo al DOM bajo un elemento visible, por ejemplo usando ʻappendChild`.
✅ ¿Por qué necesitamos clonar la plantilla antes de adjuntarla al DOM? ¿Qué crees que pasaría si nos salteáramos este paso?
Tarea
Cree un nuevo archivo llamado app.js
en la carpeta de su proyecto e importe ese archivo en la sección <head>
de su HTML:
<script src="app.js" defer></script>
Ahora en app.js
, crearemos una nueva función updateRoute
:
function updateRoute(templateId) {
const template = document.getElementById(templateId);
const view = template.content.cloneNode(true);
const app = document.getElementById('app');
app.innerHTML = '';
app.appendChild(view);
}
Lo que hacemos aquí son exactamente los 3 pasos descritos anteriormente. Instalamos la plantilla con el id templateId
y colocamos su contenido clonado dentro de nuestro marcador de posición de la aplicación. Tenga en cuenta que necesitamos usar cloneNode (true)
para copiar todo el subárbol de la plantilla.
Ahora llame a esta función con una de las plantillas y observe el resultado.
updateRoute('login');
✅ ¿Cuál es el propósito de este código app.innerHTML = '';
? ¿Qué pasa sin él?
Creando rutas
Cuando hablamos de una aplicación web, llamamos Enrutamiento la intención de asignar URL a pantallas específicas que deben mostrarse. En un sitio web con varios archivos HTML, esto se hace automáticamente ya que las rutas de los archivos se reflejan en la URL. Por ejemplo, con estos archivos en la carpeta de su proyecto:
mywebsite/index.html
mywebsite/login.html
mywebsite/admin/index.html
Si crea un servidor web con mywebsite
como raíz, la asignación de URL será:
https://site.com --> mywebsite/index.html
https://site.com/login.html --> mywebsite/login.html
https://site.com/admin/ --> mywebsite/admin/index.html
Sin embargo, para nuestra aplicación web estamos usando un solo archivo HTML que contiene todas las pantallas, por lo que este comportamiento predeterminado no nos ayudará. Tenemos que crear este mapa manualmente y actualizar la plantilla mostrada usando JavaScript.
Tarea
Usaremos un objeto simple para implementar un [mapa] (https://en.wikipedia.org/wiki/Associative_array) entre las rutas de URL y nuestras plantillas. Agregue este objeto en la parte superior de su archivo app.js
.
const routes = {
'/login': { templateId: 'login' },
'/dashboard': { templateId: 'dashboard' },
};
Ahora modifiquemos un poco la función updateRoute
. En lugar de pasar directamente el templateId
como argumento, queremos recuperarlo mirando primero la URL actual y luego usar nuestro mapa para obtener el valor de ID de plantilla correspondiente. Podemos usar window.location.pathname
para obtener solo la sección de ruta de la URL.
function updateRoute() {
const path = window.location.pathname;
const route = routes[path];
const template = document.getElementById(route.templateId);
const view = template.content.cloneNode(true);
const app = document.getElementById('app');
app.innerHTML = '';
app.appendChild(view);
}
Aquí mapeamos las rutas que declaramos a la plantilla correspondiente. Puede probar que funciona correctamente cambiando la URL manualmente en su navegador.
✅ ¿Qué sucede si ingresa una ruta desconocida en la URL? ¿Cómo podríamos solucionar esto?
Añadiendo navegación
El siguiente paso para nuestra aplicación es agregar la posibilidad de navegar entre páginas sin tener que cambiar la URL manualmente. Esto implica dos cosas:
- Actualización de la URL actual
- Actualización de la plantilla mostrada en función de la nueva URL
Ya nos ocupamos de la segunda parte con la función updateRoute
, así que tenemos que averiguar cómo actualizar la URL actual.
Si bien el elemento de anclaje HTML <a>
se puede utilizar para crear hipervínculos a diferentes URL, podemos ' No use eso aquí, ya que hará que el navegador vuelva a cargar el HTML.
En su lugar, tendremos que usar JavaScript y más específicamente el history.pushState
que permite actualizar la URL y cree una nueva entrada en el historial de navegación, sin volver a cargar el HTML.
Tarea
Creemos una nueva función que podamos usar para navegar en nuestra aplicación:
function navigate(path) {
window.history.pushState({}, path, window.location.origin + path);
updateRoute();
}
Este método primero actualiza la URL actual según la ruta proporcionada y luego actualiza la plantilla. La propiedad window.location.origin
devuelve la raíz de la URL, lo que nos permite reconstruir una URL completa a partir de una ruta determinada.
Ahora que tenemos esta función, podemos solucionar el problema que tenemos si una ruta no coincide con ninguna ruta definida. Modificaremos la función updateRoute
agregando un respaldo a una de las rutas existentes si no podemos encontrar una coincidencia.
function updateRoute() {
const path = window.location.pathname;
const route = routes[path];
if (!route) {
return navigate('/login');
}
...
Si no se puede encontrar una ruta, ahora lo redireccionaremos a la página de login
.
Completemos el sistema de navegación agregando enlaces a nuestros botones login y logout en el HTML.
<button onclick="navigate('/dashboard')">Login</button>
...
<button onclick="navigate('/login')">Logout</button>
Usando el atributo [onclick
] (https://developer.mozilla.org/en-US/docs/Web/API/GlobalEventHandlers/onclick) enlaza el evento click
al código JavaScript, aquí la llamada al navigate()
función.
Intente hacer clic en estos botones, ahora debería poder navegar entre las diferentes pantallas de su aplicación.
✅ El método history.pushState
es parte del estándar HTML5 y está implementado en todos los navegadores modernos. Si está creando una aplicación web para navegadores más antiguos, hay un truco que puede usar en lugar de esta API: usar un hash (#
) antes la ruta puede implementar un enrutamiento que funcione con la navegación de anclaje regular y no recargue la página, ya que su propósito era crear enlaces internos dentro de una página.
Manejo de los botones de avance y retroceso del navegador
El uso de history.pushState
crea nuevas entradas en el historial de navegación del navegador. Puede verificar que manteniendo presionado el botón de retroceso de su navegador, debería mostrar algo como esto:
Si intenta hacer clic en el botón Atrás varias veces, verá que la URL actual cambia y el historial se actualiza, pero se sigue mostrando la misma plantilla.
Eso es porque no sabemos que necesitamos llamar a updateRoute()
cada vez que cambia el historial. Si echas un vistazo a la history.pushState
documentation, puedes ver que si el estado cambia - lo que significa que nos mudamos a una URL diferente - se activa el evento popstate
. Lo usaremos para solucionar ese problema.
Tarea
Para asegurarnos de que la plantilla mostrada se actualice cuando cambie el historial del navegador, adjuntaremos una nueva función que llama a updateRoute()
. Lo haremos en la parte inferior de nuestro archivo app.js
:
window.onpopstate = () => updateRoute();
updateRoute();
Nota: utilizamos una función de flecha aquí para declarar nuestro controlador de eventos
popstate
por concisión, pero un la función regular funcionaría igual.
Ahora intente utilizar los botones de avance y retroceso de sus navegadores y compruebe que esta vez lo que se muestra está actualizado correctamente.
🚀 Desafío
Agregue una nueva plantilla y ruta para una tercera página que muestre los créditos de esta aplicación.
Post-lecture prueba
Revisión y autoestudio
Tarea: Mejorar el enrutamiento