Saltearse al contenido

Navegación

Muchas aplicaciones web modernas se construyen como «aplicaciones de página única» (SPA). En estas aplicaciones, cada página renderizada por la aplicación ya no requiere una recarga completa de la página del navegador, evitando la sobrecarga de volver a descargar activos JavaScript y CSS en cada solicitud.

La alternativa a las aplicaciones de una sola página son las aplicaciones multipágina. En estas aplicaciones, cada vez que un usuario hace clic en un enlace, una página HTML completamente nueva es solicitada y renderizada en el navegador.

Mientras que la mayoría de las aplicaciones PHP han sido tradicionalmente aplicaciones multipágina, Livewire ofrece una experiencia de aplicación de una sola página a través de un simple atributo que puedes añadir a los enlaces de tu aplicación: wire:navigate.

Uso Básico

Exploremos un ejemplo de uso de wire:navigate. A continuación se muestra un típico archivo de rutas Laravel (routes/web.php) con tres componentes Livewire definidos como rutas:

use App\Livewire\Dashboard;
use App\Livewire\ShowPosts;
use App\Livewire\ShowUsers;
Route::get('/', Dashboard::class);
Route::get('/posts', ShowPosts::class);
Route::get('/users', ShowUsers::class);

Al añadir wire:navigate a cada enlace de un menú de navegación de cada página, Livewire evitará el manejo estándar del clic del enlace y lo sustituirá por su propia versión, más rápida:

<nav>
<a href="/" wire:navigate>Dashboard</a>
<a href="/posts" wire:navigate>Posts</a>
<a href="/users" wire:navigate>Users</a>
</nav>

A continuación se muestra un desglose de lo que ocurre cuando se hace clic en un enlace wire:navigate:

  • El usuario hace clic en un enlace
  • Livewire impide que el navegador visite la nueva página
  • En su lugar, Livewire solicita la página en segundo plano y muestra una barra de carga en la parte superior de la página
  • Cuando se ha recibido el HTML de la nueva página, Livewire sustituye la URL de la página actual, la etiqueta <title> y el contenido de <body> por los elementos de la nueva página
  • Esta técnica da lugar a tiempos de carga de página mucho más rápidos -a menudo el doble- y hace que la aplicación “parezca” una aplicación de página única con JavaScript.

Redirecciones

Cuando uno de sus componentes Livewire redirige a los usuarios a otra URL dentro de su aplicación, también puede indicar a Livewire que utilice su funcionalidad wire:navigate para cargar la nueva página. Para ello, proporcione el argumento navigate al método redirect():

return $this->redirect('/posts', navigate: true);

Ahora, en lugar de utilizar una petición de página completa para redirigir al usuario a la nueva URL, Livewire sustituirá el contenido y la URL de la página actual por la nueva.

Prefetching de enlaces

Por defecto, Livewire incluye una estrategia suave para prefetch páginas antes de que un usuario haga clic en un enlace:

  • Un usuario pulsa el botón del ratón
  • Livewire comienza a solicitar la página
  • Levanta el botón del ratón para completar el clic
  • Livewire finaliza la solicitud y navega a la nueva página
  • Sorprendentemente, el tiempo que transcurre entre que un usuario pulsa el botón del ratón y lo levanta suele ser suficiente para cargar la mitad o incluso una página entera desde el servidor.

Si desea un enfoque aún más agresivo para la precarga, puede utilizar el modificador .hover en un enlace:

<a href="/posts" wire:navigate.hover>Posts</a>

El modificador .hover ordenará a Livewire que precargue la página después de que el usuario haya pasado el ratón por encima del enlace durante 60 milisegundos.

Persistencia de elementos entre visitas a la página

A veces, hay partes de una interfaz de usuario que es necesario persistir entre cargas de página, como los reproductores de audio o vídeo. Por ejemplo, en una aplicación de podcasting, un usuario puede querer seguir escuchando un episodio mientras navega por otras páginas.

Puede conseguir esto en Livewire con la directiva @persist.

Envolviendo un elemento con @persist y proporcionándole un nombre, cuando se solicita una nueva página utilizando wire:navigate, Livewire buscará un elemento en la nueva página que tenga un @persist coincidente. En lugar de reemplazar el elemento de forma normal, Livewire utilizará el elemento DOM existente de la página anterior en la nueva página, preservando cualquier estado dentro del elemento.

Este es un ejemplo de un elemento reproductor <audio> que se mantiene a través de las páginas utilizando @persist:

@persist('player')
<audio src="{{ $episode->file }}" controls></audio>
@endpersist

Si el HTML anterior aparece en ambas páginas -la actual y la siguiente-, el elemento original se reutilizará en la nueva página. En el caso de un reproductor de audio, la reproducción de audio no se interrumpirá al navegar de una página a otra.

Tenga en cuenta que el elemento persistente debe colocarse fuera de sus componentes Livewire. Una práctica común es colocar el elemento persistente en su diseño principal, como resources/views/components/layouts/app.blade.php.

resources/views/components/layouts/app.blade.php
<!DOCTYPE html>
<html lang="{{ str_replace('_', '-', app()->getLocale()) }}">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>{{ $title ?? 'Page Title' }}</title>
</head>
<body>
<main>
{{ $slot }}
</main>
@persist('player')
<audio src="{{ $episode->file }}" controls></audio>
@endpersist
</body>
</html>

Resaltar enlaces activos

Es posible que esté acostumbrado a resaltar el enlace de la página activa en ese momento en una barra de navegación utilizando Blade del lado del servidor de esta forma:

<nav>
<a href="/" class="@if (request->is('/')) font-bold text-zinc-800 @endif">Dashboard</a>
<a href="/posts" class="@if (request->is('/posts')) font-bold text-zinc-800 @endif">Posts</a>
<a href="/users" class="@if (request->is('/users')) font-bold text-zinc-800 @endif">Users</a>
</nav>

Sin embargo, esto no funcionará dentro de los elementos persistentes, ya que se reutilizan entre cargas de página. En su lugar, debe utilizar la directiva wire:current de Livewire para resaltar el enlace activo en ese momento.

Simplemente pase cualquier clase CSS que desee aplicar al enlace activo a wire:current:

<nav>
<a href="/dashboard" ... wire:current="font-bold text-zinc-800">Dashboard</a>
<a href="/posts" ... wire:current="font-bold text-zinc-800">Posts</a>
<a href="/users" ... wire:current="font-bold text-zinc-800">Users</a>
</nav>

Ahora, cuando se visite la página /posts, el enlace “Posts” tendrá un tratamiento de fuente más fuerte que los otros enlaces.

Más información en la documentación de wire:current.

Conservar la posición de desplazamiento

Por defecto, Livewire conservará la posición de desplazamiento de una página cuando navegue hacia delante y hacia atrás entre páginas. Sin embargo, a veces es posible que desee conservar la posición de desplazamiento de un elemento individual que está persistiendo entre cargas de página.

Para ello, debe añadir wire:scroll al elemento que contiene una barra de desplazamiento, de la siguiente manera:

@persist('scrollbar')
<div class="overflow-y-scroll" wire:scroll>
<!-- ... -->
</div>
@endpersist

JavaScript hooks

Cada navegación de página activa tres hooks del ciclo de vida:

  • livewire:navigate
  • livewire:navigating
  • livewire:navigated

Es importante tener en cuenta que estos tres ganchos se activan en todo tipo de navegaciones. Esto incluye la navegación manual utilizando Livewire.navigate(), la redirección con la navegación activada, y las pulsaciones de los botones atrás y adelante en el navegador.

Aquí hay un ejemplo de registro de escuchas para cada uno de estos eventos:

document.addEventListener("livewire:navigate", (event) => {
// Se activa cuando se activa una navegación.
// Puede "anularse" (impedir que se realice la navegación):
event.preventDefault();
// Contiene contexto útil sobre el disparador de navegación:
let context = event.detail;
// Un objeto URL del destino previsto de la navegación...
context.url;
// Un booleano [true/false] que indica si esta navegación
// ha sido iniciada por una navegación hacia atrás/adelante (estado histórico)...
context.history;
// Un booleano [true/false] que indica si existe o no
// versión en caché de esta página que se utilizará en lugar de
// obtener una nueva mediante un viaje de ida y vuelta por la red...
context.cached;
});
document.addEventListener("livewire:navigating", () => {
// Se activa cuando un nuevo HTML está a punto de ser intercambiado en la página...
// Este es un buen lugar para mutar cualquier HTML antes de que la página
// sea navegada...
});
document.addEventListener("livewire:navigated", () => {
// Se activa como paso final de cualquier navegación de página...
// También se activa al cargar la página en lugar de "DOMContentLoaded"...
});

Visitar manualmente una nueva página

Además de wire:navigate, puede llamar manualmente al método Livewire.navigate() para activar la visita a una nueva página utilizando JavaScript:

<script>// ... Livewire.navigate('/new/url')</script>

Uso con software de análisis

Al navegar por páginas utilizando wire:navigate en su aplicación, cualquier etiqueta <script> en el <head> sólo se evalúa cuando la página se carga inicialmente.

Esto crea un problema para el software de análisis como Fathom Analytics. Estas herramientas dependen de que se evalúe un fragmento <script> en cada cambio de página, no solo en el primero.

Herramientas como Google Analytics son lo suficientemente inteligentes como para manejar esto de forma automática, sin embargo, cuando se utiliza Fathom Analytics, debe agregar data-spa="auto" a su etiqueta script para asegurarse de que cada visita a la página se rastrea correctamente:

<head>
<!-- ... -->
<!-- Fathom Analytics -->
@if (! config('app.debug'))
<script src="https://cdn.usefathom.com/script.js" data-site="ABCDEFG" data-spa="auto" defer></script>
@endif
</head>

Evaluación de scripts

Cuando se navega a una nueva página utilizando wire:navigate, parece como si el navegador hubiera cambiado de página; sin embargo, desde la perspectiva del navegador, técnicamente todavía se está en la página original.

Debido a esto, los estilos y scripts se ejecutan normalmente en la primera página, pero en las páginas siguientes, puede que tengas que modificar la forma en que normalmente escribes JavaScript.

He aquí algunas advertencias y situaciones que debe tener en cuenta al utilizar wire:navigate.

No confíes en DOMContentLoaded

Es una práctica común colocar JavaScript dentro de un receptor de eventos DOMContentLoaded para que el código que desea ejecutar sólo se ejecute después de que la página se haya cargado completamente.

Cuando se utiliza wire:navigate, DOMContentLoaded sólo se activa en la primera visita a la página, no en las siguientes.

Para ejecutar código en cada visita a la página, cambia cada instancia de DOMContentLoaded por livewire:navigated:

/* NO */ document.addEventListener('DOMContentLoaded', () => {
/* SI */ document.addEventListener('livewire:navigated', () => {
// ...
})

Escuchar este evento es útil para cosas como inicializar librerías de terceros.

Los scripts en <head> se cargan una vez

Si dos páginas incluyen la misma etiqueta <script> en el <head>, ese script sólo se ejecutará en la visita inicial a la página y no en las siguientes.

<!-- Página uno -->
<head>
<script src="/app.js"></script>
</head>
<!-- Página dos -->
<head>
<script src="/app.js"></script>
</head>

Se evalúan los nuevos scripts <head>.

Si una página posterior incluye una nueva etiqueta <script> en el <head> que no estaba presente en el <head> de la visita a la página inicial, Livewire ejecutará la nueva etiqueta <script>.

En el siguiente ejemplo, la página dos incluye una nueva biblioteca JavaScript para una herramienta de terceros. Cuando el usuario navegue a la página dos, se evaluará esa biblioteca.

<!-- Página uno -->
<head>
<script src="/app.js"></script>
</head>
<!-- Página dos -->
<head>
<script src="/app.js"></script>
<script src="/third-party.js"></script>
</head>

Recarga cuando cambian los assets

Es una práctica común incluir un hash de versión en el nombre del archivo JavaScript principal de una aplicación. Esto asegura que después de desplegar una nueva versión de su aplicación, los usuarios recibirán el activo JavaScript fresco, y no una versión antigua servida desde la caché del navegador.

Pero, ahora que está utilizando wire:navigate y cada visita a la página ya no es una carga de página nueva del navegador, es posible que sus usuarios sigan recibiendo JavaScript obsoleto después de las implementaciones.

Para evitarlo, puede añadir data-navigate-track a una etiqueta <script> en <head>:

<!-- Página uno -->
<head>
<script src="/app.js?id=123" data-navigate-track></script>
</head>
<!-- Página dos -->
<head>
<script src="/app.js?id=456" data-navigate-track></script>
</head>

Cuando un usuario visite la página dos, Livewire detectará un activo JavaScript nuevo y activará una recarga completa de la página del navegador.

Si está utilizando el plug-in Vite de Laravel para agrupar y servir sus activos, Livewire añade data-navigate-track a las etiquetas de activos HTML renderizados automáticamente. Puedes continuar haciendo referencia a tus activos y scripts de forma normal:

<head>
@vite(['resources/css/app.css', 'resources/js/app.js'])
</head>

Livewire inyectará automáticamente data-navigate-track en las etiquetas HTML renderizadas.

Los scripts del <body> se reevalúan Dado que Livewire reemplaza todo el contenido del <body> en cada nueva página, se ejecutarán todas las etiquetas <script> de la nueva página:

<!-- Página uno -->
<body>
<script>
console.log("Se ejecuta la página uno");
</script>
</body>
<!-- Página dos -->
<body>
<script>
console.log("Se ejecuta la página dos");
</script>
</body>

Si tiene una etiqueta <script> en el <body> que sólo desea que se ejecute una vez, puede añadir el atributo data-navigate-once a la etiqueta <script> y Livewire sólo la ejecutará en la visita inicial a la página:

<script data-navigate-once>
console.log("Runs only on page one");
</script>

Personalizar la barra de progreso

Cuando una página tarda más de 150ms en cargarse, Livewire mostrará una barra de progreso en la parte superior de la página.

Puede personalizar el color de esta barra o desactivarla en el archivo de configuración de Livewire (config/livewire.php):

'navigate' => [
'show_progress_bar' => false,
'progress_bar_color' => '#2299dd',
],