Vue, como muchos otros frameworks para el desarrollo web (Angular, React) también tiene un sistema para crear rutas.

Vue permite crear páginas web SPA, es decir, el usuario tiene la sensación de que está navegando entre las páginas pero lo que de verdad ocurre es que Vue por debajo está cambiando el HTML al vuelo sin tener que recargar la página.

Por ejemplo, si estás en la página principal de una aplicación SPA y navegas a la URL /users, Vue lo que hace es renderizar el componente asociado a esa ruta en la página web. Como ese componente ya lo tiene cargado el cambio entre páginas es inmediato.

Para conseguir esto, el creador del Vue router (que es español por cierto) ha desarrollado un conjunto de utilidades para crear rutas en Vue. En un fichero configuras las rutas que quieres crear y las asocias a componentes que se cargarán cuando el usuario navegue a la ruta.

Cómo funciona el vue-router

Si has instalado Vue con Vue CLI 🚧 y has seleccionado el método manual, te habrá salido la opción de instalar el vue-router. Si no lo tienes instalado no te preocupes porque vamos a ver cómo se instala.

Antes de nada, para saber si lo tienes instalado mira en el archivo package.json si tienes dentro de la sección dependencias un paquete llamado:

"vue-router": "^3.0.3"

En mi caso tengo la versión 3.0.3 pero tú puedes tener otra versión, no pasa nada.

Si no tienes instalado vue-router lo que tienes que hacer es instalarlo dentro del proyecto, para ello, mediante línea de comandos ejecuta:

npm install vue-router --save

A continuación, lo que tienes que hacer es crear un archivo llamado router.js dentro de la carpeta src, al mismo nivel que el main.js.

Dentro del archivo lo primero que tienes que hacer es importar Vue y vue-router y hacer que vue use el router, así:

import Vue from "vue";
import VueRouter from "vue-router";

Vue.use(VueRouter);

Si el vue-router lo instalaste con vue-cli al crear el proyecto este archivo ya lo tendrás.

Las rutas se crean en un array con esta sintaxis:

const routes = [
  {
    path: "/",
    name: "home",
    component: Home,
  },
];

En este caso hay una sola ruta, la ruta raíz, en otras palabras, la que se abre al abrir la página.

Como ves cada ruta se crea en forma de objeto con propiedades. En el path indicas la ruta que quieres que se use (por ejemplo "/users"), en el name puedes darle un nombre a la ruta para identificarla posteriormente, y en el component pones el componente que quieres que se use en esa ruta, así que tendrás que importarlo de esta forma:

import Home from "@/views/Home.vue";

Si te fijas las rutas las importo desde una carpeta llamada views dentro del src. Esto se hace para poder identificar bien qué componentes se encargan de cada una de las vistas.

Si quieres localizar el componente que se encarga de renderizar la ruta /users lo único que tienes que hacer es ir a carpeta views para buscar un componente llamado Users o parecido.

Debajo de las rutas, en el mismo fichero, tienes que meter esto para que Vue pueda usar las rutas que acabas de crear:

const router = new VueRouter({
  mode: "history",
  routes,
});

export default router;

Se hace el export para que en el main.js podamos pasar las rutas a Vue, es decir, dentro del archivo main.js del src tienes que meter esto para que funcione:

import Vue from "vue";
import App from "./App.vue";
import router from "./router";

new Vue({
  router,
  render: (h) => h(App),
}).$mount("#app");

Y listo, con esto ya tendríamos una ruta funcionando en Vue. Si quieres añadir más rutas lo que tienes que hacer simplemente es añadir más objetos al array de rutas del archivo router.js que acabas de crear, así:

import Vue from "vue";
import VueRouter from "vue-router";

import Home from "./views/Home.vue";
import Users from "./views/Users.vue";

Vue.use(VueRouter);

const routes = [
  {
    path: "/",
    name: "home",
    component: Home,
  },
  {
    path: "/users",
    name: "users",
    component: Users,
  },
];

const router = new VueRouter({
  mode: "history",
  routes,
});

export default router;

Cuando navegues a la ruta http://localhost:8080/users se cargará el componente Users de la carpeta views y por tanto se verá lo que haya en ese componente. Al navegar a http://localhost:8080/ se cargará el componente Home.

Redirecciones y alias

Además, el vue router permite crear redirecciones desde unas rutas a otras, por ejemplo:

{
  path: "/404",
  redirect: "/error"
}

También puedes crear la redirección usando el nombre de la ruta que has definido:

{
  path: "/404",
  redirect: { name: 'error' }
}

La redirección lo que hace es cambiar al usuario de ruta cuando navegue a esa ruta. Aparte de las redirecciones también existen los alias, que son parecidos,solo que mantiene al usuario en la ruta pero con el componente de otra, por ejemplo:

{
  path: "/error",
  component: Error,
  alias: "404"
}

El ccódigo de arriba quiere decir que cuando el usuario navegue a la ruta /404 se cargará el componente de Error (igual que para la ruta /error) y mantendrá al usuario en la ruta /error.

Cómo navegar a rutas desde componentes

Otra cosa muy importante de una aplicación web es la posibilidad de navegar desde los componentes a otras rutas, al pulsar un botón por ejemplo, o cuando ocurra una acción. Vue router también permite navegar desde código a las rutas que tienes definidas.

Navegando desde la vista. Router link

Al instalar vue router, se crea una etiqueta HTML especial para poder navegar a las rutas desde el Sistema de vistas de Vue llamada router-link. Veamos un ejemplo:

<router-link to="/about">Link a la página de about</router-link>

También puedes navegar a una ruta usando su nombre (el parámetro name que has configurado antes en el array de rutas), esto es interesante porque si decides cambiar la url de la ruta, vas a poder seguir navegando correctamente porque el nombre sigue siendo el mismo.

<router-link :to="{ name: 'user'}">User</router-link>

Fíjate que he puesto los dos puntos antes de el atributo to para poder pasar un objeto de javascript.

Incluso puedes pasar una variable definida en el data o variable computada para decidir a qué ruta ir:

<router-link :to="user">User</router-link>

En este caso se creará un enlace a la ruta definida en la variable user.

Esta etiqueta renderizará una etiqueta <a> con el href ya configurado a la ruta que especifiques dentro del to.

Router push

Esta forma es la más utilizada para navegar hacia rutas desde la lógica de un componente. Lo que hace simplemente es navegar a la ruta que le pasemos al método. Igual que pasaba con el router link, aquí también puedes pasar un objeto para poder usar el nombre de la ruta en lugar de su ruta.

// Con la URL de la ruta
this.$router.push("home");

// Con el nombre de la ruta
this.$router.push({ path: "home" });

No necesitas importar nada, Vue creará la variable $router dentro del this con la instancia del router para que puedas navegar desde los componentes.

Router replace

Funciona igual que router push pero con una diferencia. Con el push se navega a la ruta y se guarda la ruta actual en la historia del navegador para que el usuario pueda volver a la página anterior pulsando sobre el botón de atrás en el navegador.

Con router replace el usuario al pulsar sobre el enlace no podrá volver a la página anterior. Esto se suele usar por ejemplo cuando haces un logout del usuario o cuando queremos sacarlo de una página y no queremos que pueda echar hacia atrás la historia del navegador.

// Con la URL de la ruta
this.$router.replace("home");

// Con el nombre de la ruta
this.$router.replace({ path: "home" });

Router go

Pasando un número, sirve para decidir si queremos retroceder o avanzar en la historia del navegador del usuario.

// Esta instrucción lo que hará sera hacer que el usuario vuelva a la página anterior.
this.$router.go(-1);

// Esta instrucción hará que el usuario avance una página en la historia del navegador en caso de que se pueda
this.$router.go(1);

Aspectos avanzados de Vue router

Ahora vamos a ver funcionalidad del vue router un poco más compleja. No te alarmes porque no es muy difícil de entender.

Pasar parámetros a las rutas

Una cosa muy interesante que puedes hacer en las rutas es pasar parámetros en la query de las rutas, por ejemplo, imagina que quieres tener una ruta llamada usuarios en la que se muestran todos los usuarios y además quieres que desde otra página se enlace a esa vista de usuarios pero en ese caso quieres que los usuarios se ordenen de forma descente, es decir, quieres poder decidir antes de navegar a la ruta si quieres ordenar de forma ascendente o descencente.

Para este tipo de casos te puede servir pasar parámetros en las rutas. Estos parámetros funcionan igual que los parámtros en los GET de las APIS. En nuestro ejemplo la ruta se formaría así: /users/?sort=asc.

Vue te permite añadir este tipo de funcionalidad sin tener que crear las rutas manualmente. Para este ejemplo solo necesitas crear la ruta de usuarios como lo has hecho hasta ahora:

  {
    path: "/users",
    name: "users",
    component: PageUsers
  }

Para navegar a esta ruta, en el router link tienes que poner:

<router.link :to="{path: 'users', query: {sort: 'desc'}}"></router-link>

O si usas vue-router push o replace:

router.push({ path: "users", query: { sort: "asc" } });

Si te fijas, solo tienes que pasar un objeto query donde el nombre de cada clave será el valor de ese campo en la query de la url.

Dentro del componente de la lista de usuarios, en nuestro ejemplo, puedes acceder al valor del dato en la query de esta forma:

this.$route.query.sort;

El objeto this.route (no confundir con this.router) contiene información de la ruta en la que te encuentras en ese momento. Desde este objeto puedes acceder a todos los campos de la query en la URL. Con esto ya puedes usar esta información como necesites, por ejemplo, dentro del created o en computadas.

Por cierto, también se pueden pasar props directamente a las routas, lo explico en el artículo de los Props en Vue.

Rutas dinámicas

Otra cosa muy interesante que puedes hacer con las rutas es la posibilidad de poder crear rutas con una parte de la misma dinámica. Imagina que quieres tener una vista para mostrar los datos en detalle de un usuario. Eso significa que vas a necesitar una ruta para cada uno de los usuarios, por ejemplo: /users/1, /users/2, /users/3, /users/4...

En lugar de crear todas las rutas a mano, Vue ofrece una forma de crearlas todas de una. Lo que tienes que hacer es meter dentro de la ruta, al crearla, un campo especial. Veamos el ejemplo para los usuarios:

  {
    path: "/users/:id",
    name: "users",
    component: PageUser
  }

Fíjate que en el path de la ruta, cuando pongo el id pongo delante los dos puntos. Esto indica a Vue que esa ruta va a tener esa parte de forma dinámica. Es decir, para este ejemplo el campo id será dinámico (puedes poner el nombre que quieras, por ejemplo: /users/:name)

Para acceder dentro de ese componente al campo dinámico que hayas declarado tan solo tienes que:

this.$route.params.id;

El objeto params tiene todos los campos dinámicos que hayas declarado (en rutas anidadas puede haber varios campos dinámicos)

Por ejemplo puedes usar este campo dentro de nuestro ejemplo de vista en detalle del usuario para crear una llamada a la API al entrar en la ruta:

// ...
async created() {
  const id = this.$route.params.id;
  const response = await api.getUser(id);
  this.user = response.data;
}
// ...

Rutas hijas y rutas padre

Este caso es uno de los más típicos en las aplicaciones de Vue.

Se trata de ir anidando rutas de tal forma que varias rutas tengan un componente padre común. Imagina que tienes un panel de control en una parte de la web. Con esta estrategia puedes crear las rutas anidadas al panel de control: /admin/users, /admin/settings, etc

Además otra ventaja de esto es que en el componente padre, puedes por ejemplo poner una parte de la vista que todos los componentes hijos van a heredar. Por ejemplo en este ejemplo del panel de control, en el componente padre puedes crear el menú con enlaces a todas las páginas de tal forma que al navegar a cada una de ellas aparezca el mismo menú y no tengas código duplicado en cada una de las subpáginas.

/admin/users/                         /admin/settings
+------------------+                  +-----------------+
| Admin            |                  | Admin           |
| +--------------+ |                  | +-------------+ |
| | Users        | |  +------------>  | | Settings    | |
| |              | |                  | |             | |
| +--------------+ |                  | +-------------+ |
+------------------+                  +-----------------+

Crear rutas hijas es muy sencillo, tan solo tienes que meter rutas dentro del parámertro children en el el array de las rutas. Ejemplo:

routes: [
    { path: '/admin/', component: PageAdmin,
      children: [
        {
          path: 'users',
          component: PageAdmin
        },
        {
          path: 'settings',
          component: PageSettings
        }
      ]
  }
}

Una vez creadas las rutas, en el componente padre tienes que poner una etiqueta HTML especial para poder renderizar en ese puntoe el contendio del componente hijo:

// Admin.vue
<div>
  <h1>Admin page</h1>
  <p>Este contenido se renderiza en las dos páginas</p>
  <router-view></router-view>
</div>

Todo el contendio que pongas en el componente padre se renderizará en las dos rutas hijas (/admin/users y en /admin/settings). Justo debajo de ese título se renderizará el componente hijo. Si no pones el <router-view> no se renderizarán los componentes hijos dentro del padre.

Ruta para páginas de 404 not found

Para finalizar, vamos a ver cómo se redirije a los usuarios si entran en una ruta que no exista dentro de las rutas declaradas. Vue nos lo pone fácil y solo tenemos que crear una ruta con un path especial:

routes: [
  { path: "/", component: HomeComponent },
  // ... otras rutas ...
  { path: "*", component: PageNotFound },
];

Si Vue no hac ematch de la ruta a la que ha navegado el usuario con alguna de las declaradas, automáticamente se carga el componente declarado con el path *