En aplicaciones Vue.js, a menudo necesitamos implementar comportamientos específicos de navegación:
- Al navegar desde una página de búsqueda a una página de resultados, los resultados deben actualizarse con datos frescos.
- Al regresar de una página de detalle a la lista de resultados, debemos mantener los datos cargados previamente y restaurar la posición de desplazamiento.
Para lograr esto, utilizaremos el componente keep-alive proporcionado por Vue 2. Primero, en nuestro archivo app.vue, definimos keep-alive:
<keep-alive>
<router-view v-if="$route.meta.keepAlive"/>
</keep-alive>
<router-view v-if="!$route.meta.keepAlive"/>
Esta configuración utiliza el campo keepAlive personalizado en meta información de la ruta para determinar si el componente debe ser caché.
En nuestro archivo router/index.js, definimos la meta información:
{
path: '/lista',
name: 'ListaResultados',
component: resolve => require(['@/paginas/lista'], resolve),
meta: {
necesitaRefresco: false,
keepAlive: true
}
}
Antes de implementar la lógica de refresco o caché, revisemos los hooks de ciclo de vida relacionados con el caché:
Para componentes con keep-alive:
- Primera entrada: beforeRouteEnter -> created -> ... -> activated -> ... -> deactivated
- Entradas posteriores: beforeRouteEnter -> activated -> deactivated
El hook activated se ejecuta cada vez que el componente activado desde el caché. Implementemos nuesttra lógica:
activated() {
// Solo refrescar datos si no se debe usar caché
if(!this.$route.meta.necesitaRefresco) {
this.datosLista = []; // Limpiar datos existentes
this.cargarDatos(); // Función para obtener datos
} else {
this.$route.meta.necesitaRefresco = false;
}
}
En la página de detalle, usamos el hook beforeRouteLeave:
beforeRouteLeave(to, from, next) {
if (to.name == 'ListaResultados') {
to.meta.necesitaRefresco = true;
}
next();
}
Para manejar el caso donde navegamos a una página diferente que no es detalle y regresamos sin refrescra:
beforeRouteLeave(to, from, next) {
if (to.name == 'ListaResultados') {
to.meta.necesitaRefresco = true;
}
next();
}
Para escenarios más complejos, como eliminar un elemento en la página de detalle que requiere refrescar la lista al regresar:
data() {
return {
elementoEliminado: false
}
},
beforeRouteLeave(to, from, next) {
if (to.name == 'ListaResultados') {
to.meta.necesitaRefresco = this.elementoEliminado;
}
next();
},
methods: {
eliminarElemento() {
// Lógica de eliminación
this.elementoEliminado = true;
this.$router.go(-1);
}
}
Finalmente, para manejar la posición de scroll:
scrollBehavior(to, from, savedPosition) {
if (savedPosition) {
return savedPosition;
} else {
if (from.meta.keepAlive) {
from.meta.posicionGuardada = document.body.scrollTop;
}
return { x: 0, y: to.meta.posicionGuardada || 0 };
}
}