Versiones comparadas

Clave

  • Se ha añadido esta línea.
  • Se ha eliminado esta línea.
  • El formato se ha cambiado.

Tabla de contenidos

...

Para el UI del Portal de Servicios unificado, cada servicio definirá sus rutas en un archivo module.routes.js, que se situará en el directorio raíz del servicio, y tendrá esta estructura:

Rutas de un servicio

Para la navegación en Vue utilizamos el paquete vue-router. Podemos ver la documentación oficial con todos los detalles aquí.

Debemos importarlo en nuestromain.js:

Bloque de código
languagejs
import { router from './router';defineAsyncComponent } from 'vue';

const ExpedientesView = defineAsyncComponent(() => import(/* webpackChunkName: "CEXP_ExpedientesView" */'./views/ExpedientesView.vue'));

const rutaProyecto = '/consulta/expedienteacademico';

export default [
  {
    path: `${rutaProyecto}/`,
    name: 'CEXP Expedientes',
    component: ExpedientesView,
    meta: {
      requiresAuth: true,
    },
  },
  { ... },
  { ... },
];

Todos las rutas serán lazy, se cargarán los componentes cuando se navegue a ellos, para evitar que se tenga que cargar todo al inicio de la aplicación. Para eso, como vemos, utilizamos defineAsyncComponent y en el import especificamos webpackChunkName, especificando un nombre distintivo (no poner "home", por ejemplo, mejor poner como en el ejemplo, algo distintivo de tu servicio)Y también en la parte delnew Vue:

Bloque de código
languagejs
newimport Vue({
  router,
  render: h{ defineAsyncComponent } from 'vue';
 
const nombreInterno1 = defineAsyncComponent(() => h(App),
}).$mount('#app')
import(/* webpackChunkName: "nombreFragmentoEnDist1" */'./views/Componente1.vue'));
const nombreInterno2 = defineAsyncComponent(() => import(/* webpackChunkName: "nombreFragmentoEnDist2" */'./views/Componente2.vue'));

Después, como vemos, definimos la ruta base del proyecto, que utilizaremos en cada una de las rutas.

Añadir variables del proyecto (meta) para nuestras rutas. Funcionalidades extra

Por último, para las rutas que requieran estar autenticado, especificamos incluimos esto:

Bloque de código
languagejs
meta: {
    requiresAuth: true,
},

Además, existen (edición 21/02/2023) dos nuevas variables meta que se pueden añadir a cada una de nuestras rutas, :

  • needs2FA: Se añadirá a aquellas rutas que necesiten un factor doble de autenticación por parte del usuario, aunque todo este factor de autenticación deberá comprobarse en cada llamada al backend. Es para darle una mejor experiencia al usuario cuando navegue entre pantallas.
  • hiddenFeature: Se utilizará cuando queramos mostrar algo a algún usuario y que llegue hasta producción pero no esté preparado para funcionar al 100% (bien porque no se tengan datos definitivos, bien porque no haya ni backend) y se podrá activar para navegar visitando /feature-flag/nuestra/ruta Si no la activamos, enviará al usuario a un error 404.

Como con requiresAuth, no es necesario añadirlas si su valor va a ser false.

Al final, una ruta completa quedaría de este estiloPara definir las rutas, tendremos un directorio router/dentro de src/, que contendráindex.js. En él podemos definir una lista con un objeto por cada ruta, de la siguiente forma:


Bloque de código
languagejs
titleMetas disponibles
linenumberstrue
meta: {
  path: '/frameworkFundeweb'requiresAuth: true,
  needs2FA: true,
  hiddenFeature: true,
  namegroup: 'framework fundewebuser',
  componentapplication: FrameworkFundeweb'profile-data',
}

Aquí nos definimos la ruta que tendremos en la url, un nombre que incluiremos opcionalmente, para referenciarlo desde otras partes del código en lugar de escribir la ruta, y por último el componente que se mostrará cuando naveguemos a la ruta.

,


Advertencia

El name de la ruta debe ser ÚNICO EN TODO EL PROYECTO. Si hay nombres de rutas repetidos, no funcionará. Por lo tanto, tendremos que evitar nombres generales com "Home". Lo mejor que podemos hacer es poner un prefijo característico de nuestro servicio. Por ejemplo, para el servicio Consulta de Expedientes, el nombre de la única ruta que tiene es "CEXP Expedientes", utilizando CEXP para distinguirlo.


Añadir rutas al portal

Para añadir las rutas al router global de POSE, tendremos que modificar el archivo app.routes.js, situado en src/. Hay que importar el archivo previo e incluirlo al final del objeto que devuelve el router, de esta forma.

ImportUn ejemplo de fichero completo sería este:

Bloque de código
languagejs
import VuenombreRutasComponente from 'vue'
import VueRouter from  'vue-router'
import Home from '../views/Home.vue'
import Profile from './nombreGrupo/nombreProyecto/nombreComponente';

Declaración:

Bloque de código
languagejs
export default [
  ...PoseRoutes,
  ...MNCSRoutes,
  ...ultimoficheroDeRutas,  <--------../views/Profile.vue'
 
Vue.use(VueRouter);
 
const routes = [
  {
    path: "/",
    name: "home"'/:catchAll(.*)',
    component: Home...
  }
];

En la siguiente imagen se puede ver cómo ha quedado el fichero tras añadir el módulo de Mis Certificados:

Image Added

Definir sub-rutas

Podemos definir rutas hijas de una ruta ya existente, añadiéndolas al parámetro children de la ruta padre:

Bloque de código
languagejs
,
  {
    path: '"/profile'about",
    name: 'profile'"about",
    component: ProfileAbout,
    props: true
  }
]
 
const router = new VueRouter({
  mode: 'history',
  routes
})
 
export default router	children: [{path: "detalle", name: "Detalle", component: Detalle }]
  },

En este ejemplo la ruta padre sería /about, y la ruta hija /about/detalle. A la hora de definir rutas hijas, es importante tener en cuenta que el path no debe incluir la barra ("/"), pues si lo hace lo toma como lo que hay inmediatamente después de la url de nuestro sitioSi nos fijamos, podemos poner en cada ruta un campo props a true. Con esto, cuando naveguemos a esa ruta, los parámetros que se le pasen cuyo nombre coincida con un prop definido en el componente se asignará a este directamente. Es importante tener en cuenta que para hacer esto, tendremos que hacer la navegación utilizando el name, y no el path, pues si no no funciona.

Vista del router

El router habrá que incluirlo como un componente más . Así, podemos definir la parte de la pantalla que cambiará cuando se cambie de ruta, pudiendo dejar fijo, por ejemplo, un menú lateral, y que sólo se tenga que cargar el contenido de la página.Para esto, en el archivo .vue inicial, el que se carga al principio, basta con incluir (en POSE ya está incluido), así:

Bloque de código
languagexml
<router-view></router-view>

Así, esta parte de la página se sustituirá por el componente correspondiente, cambiando sólo la parte necesaria de la página sin tener que volver a cargarlo todo.

Navegar

Para relizar realizar la navegación, podríamos hacerlo concon href, pero es mejor utilizar router-link:

Bloque de código
languagexml
<router-link :to="{ name: 'nuevaComunicacion', params: { idReenviar: fila.data.id }}">

Como vemos, se le indica a dónde navegar con el nombre que hemos definido previamente para la ruta. Además podemos pasar datos como parámetro, con params. Después, en el componente al que se navega, podemos coger dichos datos referenciando a this.$route.params. En este ejemplo, el objeto que se ha pasado se cogería con this.$route.params.idReenviar.

Si queremos hacerlo de forma programática, en la parte de JavaScript concon this.$router.pusthpush():

Bloque de código
languagejs
// path
this.$router.push('/home')
 
// path
this.$router.push({ path: '/home' }) 
 
// nombre + parámetrosname
this.$router.push({ name: 'user', params: { userId: '123' } })Home' }) 

En Composition API, la sintaxis cambia, en vez de acceder a this.$router y this.$route, disponemos de useRouter() y useRoute():

Bloque de código
languagejs
<script setup>
import { userRouter, useRoute } from 'vue-router'

const router = useRouter()
const route = useRoute()
</script>

Y ya se accede como visto anteriormente, pero usando router o route:

Bloque de código
// path
router.push('/home')
 
// path
router.push({ path: '/home' }) 
 
// name
router.push({ name: 'Home' }) 


Interceptores de navegación

Vue router ofrece la posibilidad de añadir código para ejecutarlo cuando se produzca la navegación, con los navigation guards. Son una serie de métodos que podemos definir. El proceso de navegación, y el momento en el que se ejecuta cada método es el siguiente:

...

Estos métodos pueden ser globales (no los utilizaremos) o locales a cada ruta.

Interceptores globales

beforeEach

Podemos registrar interceptores de manera global para definir un comportamiento que se ejecute justo antes de producirse la navegación a cualquier ruta. Esto lo hacemos conrouter.beforeEach, de esta manera:

Bloque de código
languagejs
router.beforeEach((to, from, next) => {
	// ...
})

Los parámetros de esta función son:

  • to: objeto con la información de la ruta a la que se navega.

  • from: objeto con la información de la ruta desde la que se navega.

  • next: es una función que permite reanudar la navegación. Nos permite llamarla de diferentes maneras para tener diferentes comportamientos: next() reanuda la navegación hacia la ruta indicada en to. next('/') redirige a la ruta que se le pase como parámetro. next(false) aborta la navegación. next(new Error()) aborta la navegación y se ejecuta el callback onError.

Hay que asegurarse de que sólo se llama anext()una vez, en caso contrario podemos encontrarnos errores. Por ejemplo, esto estaríamal:

Bloque de código
languagejs
// BAD
router.beforeEach((to, from, next) => {
  if (to.name !== 'Login' && !isAuthenticated) next({ name: 'Login' })
  // if the user is not authenticated, `next` is called twice
  next()
})

Laforma correctasería esta:

Bloque de código
languagejs
// GOOD
router.beforeEach((to, from, next) => {
  if (to.name !== 'Login' && !isAuthenticated) next({ name: 'Login' })
  else next()
})

Se pueden registrar múltiples interceptores del mismo tipo, y estos se ejecutarán en orden de aparición, es decir, el primero en registrarse es el primero que se ejecuta.

Los interceptores nos pueden venir bien para comprobar algún estado global de la aplicación, como la autorización del usuario.

beforeResolve

Se pueden registrar estos interceptores con router.beforeResolve, de la misma forma que los beforeEach. La diferencia es que estos se ejecutan justo antes de que se confirme la navegación, después de haber ejecutado los interceptores de ruta y de componentes, y que los componentes de ruta asíncronos se resuelvan.

afterEach

También se pueden registrar globalmente interceptoresafterEachque se ejecutarán después de confirmar la navegación. Se definen como losbeforeEach, pero sin un parámetronext, pues ya se ha confirmado la navegación:

...

languagejs

...

Interceptores por ruta

Se pueden definir interceptores beforeEnter directamente en el objeto que define las rutas, con la misma notación que los interceptores globales before:

Bloque de código
languagejs
{
    path: '/foo',
    component: Foo,
    beforeEnter: (to, from, next) => {
    // ...
}

Interceptores por componente

Se pueden definir interceptores de navegación dentro de los componentes que se pasan a las rutas, con las siguientes opciones:

...