Enrutamiento con Vue.js

Aunque ya lo hemos visto en otras publicaciones, el routing o enrutamiento es la forma que tienen las aplicaciones web de responder, dependiendo de la URL por la cual se accede.

Por lo general esto se define desde el lado del backend, en donde el servidor consulta la URL y el método, y responde devolviendo al cliente un HTML, un JSON, un XML, un archivo, etc. Sin embargo en este caso en particular, estamos refiriéndonos a Vue.js, que funciona en la máquina del cliente.

Por esto usaremos una librería llamada: vue-router, la cual nos permitirá indicar el contenido visual, dependiendo de una lista de URL. Comencemos:

Lo primero que haremos es incluir Twitter Bootstrap, para tener un aspecto visual más agradable:

<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" integrity="sha384-BVYiiSIFeK1dGmJRAkycuHAHRg32OmUcww7on3RYdg4Va+PmSTsz/K68vbdEjh4u" crossorigin="anonymous">

También vamos a incluir nuestra librería de Vue:

<script src="https://unpkg.com/vue/dist/vue.js"></script>

Y por su puesto la que nos permitirá enrutar:

<script src="https://unpkg.com/vue-router/dist/vue-router.js"></script>

Finalmente, como haremos un ejemplo con ajax, vamos a incluir Axios, librería que vimos en publicaciones anteriores:

<script src="https://unpkg.com/axios/dist/axios.min.js"></script>

Bueno, hasta aquí lo necesario para comenzar, ahora vamos a aclarar un punto: En realidad, cuando las URL cambian en nuestro navegador, la página que habíamos visitado finaliza, dando inicio a la siguiente, sin embargo en este caso en particular, aunque la URL cambia, gracias las anclas (#) nuestra aplicación siempre va a funcionar en la misma página.

Vamos a incluir el código HTML base:

<div id="app" class="container">
 <h1> Router </h1>
 <ul class="nav nav-pills">
    <li role="presentation">
       <router-link to="/principal">Principal</router-link>
    </li>
    <li role="presentation">
       <router-link to="/posts">Ver publicaciones</router-link>
    </li>
 </ul>
 <router-view></router-view>
</div>

El tag router-view, es donde va a cargar el contenido dependiendo de la URL, el resto va a mostrarse siempre.

Además mediante el otro tag router-link y la propiedad to, tendrá una suerte de enlace que va a indicar a que URL vamos a visitar. En este ejemplo tendremos tres URL:

‘/principal’ y ‘/post’, la primera con un mensaje de bienvenida y la segunda con una lista de publicaciones, y una última URL, ‘/post/:id’ con contenido dinámico, que dependiendo de un ID va a leer uno de esos post:

  • ‘/principal’ –> Sólo tendrá un mensaje de bienvenida
  • ‘/post’ –> Una lista de publicaciones
  • ‘/post/:id’ –> Tendrá un contenido dinámico, que dependiendo de un ID va a leer una publicación en particular.

Componentes

Los componentes nos permitirán definir un apartado visual, por lo cual, al ruteador tendremos que indicarle qué componente mostrar, dependiendo de cada URL que se visita.

const Principal = {
 template: `
    <div>
       <h2> Esta es mi página principal </h2>
       <p> Simple ejemplo de <a href="https://vuejs.org/v2/guide/routing.html" target="_blank">Vue router</a>. </p>
    </div>
 `
};

Esta será nuestra página principal, el template, que será el apartado html que va a mostrar se define justamente con la propiedad, valga la redundancia, template. No vamos a guardar ninguna información, ni realizar ninguna acción.

const Posts = {
 data: function(){
    return {
       cargando: true,
       error: false,
       posts: []
    }
 },
 created: function(){
    this.recuperarPosts();
 },
 methods: {
    recuperarPosts: function(){
       var that = this;
       axios.get('https://jsonplaceholder.typicode.com/posts/')
       .then(function (response) {
          that.cargando = false;
          that.posts = response.data;
       })
       .catch(function (error) {
          that.cargando = false;
          that.error = true;
       });
    }
 },
 template: `
    <div>
       <div v-if="cargando">
          Cargando publicaciones...
       </div>
       <div v-else-if="error" class="alert alert-danger">
          Error al intentar cargar las publicaciones.
       </div>
       <div v-else>
          <h2> Publicaciones </h2>
          <table class="table table-striped">
             <thead>
                <tr>
                   <th> Id de usuario </th>
                   <th> Id </th>
                   <th> Título </th>
                   <th> </th>
                </tr>
             </thead>
             <tbody>
                <tr v-for="item in posts">
                   <td> {{ item.userId }} </td>
                   <td> {{ item.id }} </td>
                   <td> {{ item.title }} </td>
                   <td>
                      <router-link :to="'/posts/' + item.id" > Ver publicación </router-link> 
                   </td>
                </tr>
             </tbody>
          </table>
       </div>
    </div>
 `
};

En este caso va a mostrarlos una lista de publicaciones, gracias al api público de jsonplaceholder.typicode.com. Si logramos consumir el POST correctamente nos mostrará una lista de publicaciones en una tabla, de lo contrario va a mostrar un mensaje de error.

También observemos que al mostrar una publicación, se accede a otra URL en donde le pasamos el ID dinámicamente:

<router-link :to="'/posts/' + item.id" > Ver publicación </router-link>

Pasar parámetros por URL

También podemos recuperar parámetros de forma dinámica en nuestra URL, para eso vamos a crear nuestro último componente:

const Post = {
 data: function(){
    return {
       cargando: true,
        error: false,
        post: null
     }
 },
 created: function(){
    this.recuperarPost();
 },
 methods: {
    recuperarPost: function(){
       var that = this;
       var ide = this.$route.params.id;
       axios.get('https://jsonplaceholder.typicode.com/posts/' + ide)
       .then(function (response) {
          that.cargando = false;
          that.post = response.data;
       })
       .catch(function (error) {
          that.cargando = false;
          that.error = true;
       });
    }
 },
 template: `
    <div>
       <div v-if="cargando">
          Cargando publicación...
       </div>
       <div v-else-if="error" class="alert alert-danger">
          Error al intentar cargar la publicación.
       </div>
       <div v-else>
          <h2> {{ post.title }} </h2>
          <hr />
          <div class="row">
             <div class="col-md-12">
                {{ post.body }}
             </div>
          </div>
       </div>
    </div>
 `
};

Este último va a hacer algo similar que el componente que recupera todas las publicaciones, sólo que con una de éstas en particular.

También observemos cómo recuperamos el ID de la URL:

var ide = this.$route.params.id;

Ruteador

Bien, ahora que tenemos nuestros componentes, ya podemos definir nuestras URL, en donde dependiendo de cada una de éstas, usaremos un componente distinto:

const routes = [
 {path: '/', component: Principal},
 {path: '/principal', component: Principal},
 {path: '/posts', component: Posts},
 {path: '/posts/:id', component: Post}
];

Como vemos, las rutas estarán dentro de un array en donde cada posición será un objeto con el aspecto de la URL y el componente que vamos a mostrar.

{path: '/', component: Principal},
{path: '/principal', component: Principal},

El componente Principal, será nuestra página de inicio, y también vamos a acceder con la misma yendo a la URL: ‘/principal’.

También usaremos ‘/posts’, para mostrar el componente que devuelve la lista de publicaciones consumidas en el API que nombramos anteriormente:

{path: '/posts', component: Posts},

Y por último la URL con el dato dinámico pasado en la misma:

{path: '/posts/:id', component: Post}

Como vemos, :id, será el parámetro dinámico que será reemplazado por la información que se pasa de forma dinámica, esto le servirá al componente para indicarle cuál es el id de la publicación que queremos buscar.

Finalmente vamos a usar la lista routes, para agregarlas a nuestra aplicación:

const router = new VueRouter({
routes: routes
});

const app = new Vue({
router: router
}).$mount(‘#app’);

#app se refiere al id de la vista al cual vamos a agregarle la funcionalidad.

Descargar ejemplo


Deja un comentario

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *