Introducción

Vue, como muchos otros frameworks para el desarrollo web (Angular, React) también tiene un sistema para crear rutas. Como hemos explicado en capítulos anteriores, 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 el 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 Router({
  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 Router({
  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.

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.

Al instalar vue router, se crea una etiqueta HTML especial para poder navegar a las rutas, 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)

Ciclo de vida de un componente en Vue

Visto cómo crear rutas en Vue, el siguiente paso en tu aprendizaje es comprender lo que ocurre cuando entras en la ruta.

Los componentes, en todos los frameworks, tienen ciclo de vida, en otras palabras, los componentes, se crean, se cargan, se insertan en ls vista y se destruyen, y lo bueno de esto es que puedes ejecutar código en cada uno de estos estados.

Aunque Vue tiene muchos métodos para distintos estados, voy a explicar los mas habituales, los que acabarás usando siempre, ya que el resto se usan mucho menos. En este gráfico puedes ver el ciclo que sigue Vue para los componentes.

Ciclo de vida de los componentes de Vue: Created, mounted, destroyed

Por cierto, una limitación que tienen estos estados es que no puedes usar dentro arrow functions, no puedes hacer esto porque se pierde el contexto del this y ya no puedes acceder al data y a los métodos.

Si quieres hacer algo de este estilo tienes que guardarte el valor del this o hacer un bindeo del mismo.

() => this.fetchTodos()

Created

Uno de los que más se usan. Se ejecuta después de beforeCreated. En ese punto Vue ya ha cargado todas las opciones del componente y por tanto ya existe la sección data y los métodos. Aquí puedes hacer llamadas a variables y puedes ejecutar métodos.

La única pega es que en este punto Vue todavía no ha cargado la vista, no la ha renderizado y no puedes leer o modificar nada que afecte a ls vista porque todavía no existe. No puedes acceder al DOM de ese componente.

Este método se suele usar para realizar las llamadas API REST, por ejemplo si queremos pintar un array con información que provenga del backend lo que se suele hacer es dentro del created hacer la llamada y almacenar el valor de retorno de una de las variables del data. Como Vue es reactivo, cuando la vista esté cargada se pintará el array.

Veamos un ejemplo:

<script>
export default {
  data: () => ({
    info: null,
  }),
  created() {
    this.info = "Componente cargado";
  }
};
</script>

Si te fijas lo que se hace es declarar un método created, usualmente debajo de los métodos al final del componente.

Como vimos en los métodos, para acceder a las variables se utiliza el this, en este caso para poner un valor a una variable. También podemos llamar a métodos de la sección methods con el this e incluso podemos hacer uso de las propiedades *computadas.*

Mounted

A diferencia del created, en el mounted si que tenemos acceso al DOM, es decir, el computed se ejecuta exactamente cuando se termina de pintar la vista en la página web y por tanto desde aquí podemos hacer cambios en la vista.

<template>
  <a href="/link">link</a>
</template>
<script>
export default {
  data: () => ({
    info: null,
  }),
  mounted() {
    console.log(this.$el.querySelectorAll('a'));
  }
};
</script>

Si te fijas, para acceder a un elemento del DOM se puede hacer mediante la variable que crea Vue al renderizar el componente this.$el.

Si te salta un error porque no existe el elemento, una forma de asegurarse de que Vue ya ha renderizado todos los elementos del DOM es usar la función nextTick de Vue.

<template>
  <a href="/link">link</a>
</template>
<script>
export default {
  data: () => ({
    info: null,
  }),
  mounted() {
    this.$nextTick(() => {
      console.log(this.$el.querySelectorAll('a'));
    });
  }
};
</script>

La función nextTick lo que hace es dejar pasar un pequeño intervalo de tiempo, el correspondiente a un tick.

Updated

Con este método hay que tener mucho cuidado. Se ejecuta cada vez que se produce un cambio en el componente y cambia algo de la vista. Se recomienda aquí no hacer muchos cambios en el data o en la vista y utilizar propiedades computadas o watchers que veremos más adelante.

<script>
export default {
  data: () => ({
    info: null,
  }),
  updated() {
    console.log("Componente actualizado");
  }
};
</script>

Hay que tener cuidado porque puede que se ejecute más veces de las que en realidad queremos.

Destroyed

Como puedes suponer, el destroyed se ejecuta cuando eliminamos un componente, cuando ya no esta cargado. Esto puede pasar cuando cambias de vista o cuando o cuando se borra un componente del DOM porque ha sido ocultado con v-if.

<script>
export default {
  data: () => ({
    info: null,
  }),
  destroyed() {
    console.log("Componente eliminado");
  }
};
</script>

Conclusiones

Existen muchos más métodos en el ciclo de un componente de Vue como el beforeCreated o el beforeMounted, pero no he querido explicar más porque no quiero alargar demasiado el artículo. Además los que te he enseñado aquí son los que más va a usar y los otros en raras ocasiones te harán falta.

Hasta ahora ya hemos visto cómo se crean componentes, cómo crear rutas de la web y cómo controlar el ciclo de vida de los componentes, falta ver otra de las partes más importantes del desarrollo de aplicaciones wen con componentes y es la comunicación entre ellos, el paso de información. En posteriores capítulos abordaremos esta cuestión, no te lo pierdas.