Hola a tod@s, en este post vamos a crear una paginación para nuestros desarrollos con Vue. Muchas veces cuando estamos desarrollando aplicaciones nos encontramos con servicios api (o archivos locales) que al consumirlos nos devuelven muchísimos datos. Si necesitáramos mostrar en nuestra aplicación grandes cantidades de información, una solución que podemos usar seria la paginación. En este post iremos paso a paso para conseguir una paginación de manera simple (botones Anterior y Siguiente) o una paginación mas completa (numerada) utilizando una api publica.

Pasos Previos

Primero nos creamos nuevo un proyecto con el comando: vue create paginacion. A continuación, debemos de instalar el paquete de axios para poder consumir el servicio api: npm install –save axios y por ultimo, instalar el paquete que vamos a usar para la paginación: npm install vue-paginate –save

También en index.html de nuestro proyecto enlazaremos los CDN de Bootstrap:

Dentro de la etiqueta del head:

<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@4.6.1/dist/css/bootstrap.min.css" integrity="sha384-zCbKRCUGaJDkqS1kPbPd7TveP5iyJE0EjAuZQTgFLD2ylzuqKfdKlfG/eSrtxUkn" crossorigin="anonymous">

Al final del body:

<script src="https://cdn.jsdelivr.net/npm/jquery@3.5.1/dist/jquery.slim.min.js" integrity="sha384-DfXdz2htPH0lsSSs5nCTpuj/zy4C+OGpamoFVy38MVBnE+IbbVYUew+OrCXaRkfj" crossorigin="anonymous"></script>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@4.6.1/dist/js/bootstrap.bundle.min.js" integrity="sha384-fQybjgWLrvvRgtW6bFlB7jaZrFsaBXjsOMm/tB9LTS58ONXgqbR9W8oWht/amnpF" crossorigin="anonymous"></script>

Con estos pasos ya estaremos preparados para empezar.

API

Para este ejemplo vamos a consumir una api publica gratuita muy famosa que puede sernos muy útil en nuestros desarrollos para hacer pruebas. Se trata de The Cocktail DB una api que nos devuelve múltiple información sobre cocteles. Si echas un vistazo a la documentación veras que hay diferentes request, nosotros para este proyecto vamos a utilizar el de buscar cocteles por nombre.

www.thecocktaildb.com/api/json/v1/1/search.php?s=NOMBRE-DEL-COCTEL

Antes de empezar a crear los componente con vue, vamos a probar a ver lo que nos devuelve la api al buscar el coctel con el nombre margarita.

En la respuesta nos fijamos que nos devuelve un objeto llamado drinks y adentro un array con los resultados de la búsqueda. Un cóctel se compone de muchas propiedades, pero para nuestro ejemplo nosotros nos vamos a quedar con las propiedades idDrink (id del coctel), strDrink (nombre del coctel), strCategory (categoría del coctel), strAlcoholic (si un coctel tiene alcohol), strGlass (tipo de baso en donde se sirve), strInstructions (instrucciones) y strDrinkThumb (la imagen a mostrar).

Objeto con sus propiedades resumidas:

{
            "idDrink": "11007",
            "strDrink": "Margarita",
            "strCategory": "Ordinary Drink",
            "strAlcoholic": "Alcoholic",
            "strGlass": "Cocktail glass",
            "strInstructions": "Rub the rim of the glass with the lime slice to make the salt stick to it. Take care to moisten only the outer rim and sprinkle the salt on it. The salt should present to the lips of the imbiber and never mix into the cocktail. Shake the other ingredients with ice, then carefully pour into the glass.",
            "strDrinkThumb": "https://www.thecocktaildb.com/images/media/drink/5noda61589575158.jpg"
}

Creando la aplicación

Vamos a crearnos 2 paginaciones. Una simple (con botones de anterior y siguiente) y otra enumerada.

Para utilizar la librería vue-paginate, la importaremos en nuestro archivo main.js

import Vue from 'vue'
import App from './App.vue'

import VuePaginate from 'vue-paginate'
Vue.use(VuePaginate);

Vue.config.productionTip = false

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

Paginación simple

Nos creamos un componente llamado PaginacionSimple.vue y lo mostramos en nuestro App.vue.

Para utilizar vue-paginate en nuestro html usaremos 2 etiquetas: paginate para mostrar los resultados y paginate-links para mostrar la paginación.

En la etiqueta paginate vemos que tenemos las propiedades ref (que indica que es un paginador), name (el nombre), list (lo que vamos a paginar) y per (el numero de resultados a mostrar por pagina). Dentro de la etiqueta paginate hay una etiqueta ul para recorrer el array en el que vamos a guardar la respuesta de la api y una etiqueta li para mostrar el resultado.

<paginate ref="paginator" name="bebidas" :list="bebidas" :per="4" >
  <ul v-for="bebida in paginated('bebidas')" :key="bebida.id" class="list-group mx-auto" style="width:550px">
    <li class="list-group-item text-center">{{ bebida.strDrink }}</li>
  </ul>
</paginate>

A continuación, debemos poner la etiqueta paginate-links en la que vamos a mostrar los botones de anterior y siguiente. Esta etiqueta siempre se debe de mostrar después de paginate, si no nos daría un error. La etiqueta se compone de classes (aquí ponemos las clases de bootstrap), for (enlace con la paginación), show-step-link (para que muestre los botones), simple (los valores de los botones) y async (este parámetro es muy importante, se sincroniza con paginate y evita que se dibuje primero la etiqueta paginate-links, si no nos daría un error).

<paginate-links :classes="{ ul: 'pagination', li: 'page-item', a: 'page-link' }" for="bebidas" :show-step-links="true" :async="true"
              :simple="{
                prev: 'Anterior',
                next: 'Siguiente',
              }"
            >
</paginate-links>

El código completo de nuestro componente PaginacionSimple.vue quedaría así:

<template>
    <div class="container">

      <div class="row text-center text-white mb-5 mt-2">
        <div class="col-lg-7 mx-auto">
          <h1 class="display-4 text-body mb-5">Busqueda de cócteles</h1>
          <div class="d-flex justify-content-center">
            <form class="form-inline" v-on:submit.prevent="buscarCoctel()">
              <input type="text" class="form-control mr-2" placeholder="Introduce el cóctel..." v-model="nombreCoctel"/>
              <button class="btn btn-primary">Buscar</button>
            </form>
          </div>
        </div>
      </div>

      <div v-if="bebidas != null">
        <paginate ref="paginator" name="bebidas" :list="bebidas" :per="4" >
          <ul v-for="bebida in paginated('bebidas')" :key="bebida.id" class="list-group mx-auto" style="width:550px">
            <li class="list-group-item text-center">{{ bebida.strDrink }}</li>
          </ul>
        </paginate>

        <div class="d-flex justify-content-center mt-4">
          <paginate-links :classes="{ ul: 'pagination', li: 'page-item', a: 'page-link' }" for="bebidas" :show-step-links="true" :async="true"
              :simple="{
                prev: 'Anterior',
                next: 'Siguiente',
              }"
            >
          </paginate-links>
        </div>
      </div>
      <div v-else>
        <h2 class="display-5 text-center">Sin resultados</h2>
      </div>

    </div>
</template>

<script>
import axios from "axios";

export default {
  name: "PaginacionSimple",
  data() {
    return {
      bebidas: [],
      paginate: ["bebidas"],
      nombreCoctel: "",
    };
  },
  methods: {
    buscarCoctel() {
      var request = "/api/json/v1/1/search.php?s=" + this.nombreCoctel;
      var url = "https://www.thecocktaildb.com/" + request;
      axios.get(url).then((res) => {
        this.bebidas = res.data.drinks;
        console.log(this.bebidas);
      });
    },
  },
};
</script>


Paginación enumerada

En las paginaciones enumeradas lo único que cambia es la etiqueta paginate-links. Nos encontramos un nuevo parámetro: limit (el numero de botones a mostrar dividido entre el numero de resultados) con este parámetro ya no nos haría falta usar el parámetro simple.


<paginate-links :classes="{ ul: 'pagination', li: 'page-item', a: 'page-link' }" for="bebidas" :show-step-links="true" :limit="2" :async="true">

</paginate-links>
        

El código completo de nuestro componente PaginacionEnumerada.vue quedaría así:

<template>
  <div class="container py-2">
    <div class="row text-center text-white mb-5">
      <div class="col-lg-7 mx-auto">
        <h1 class="display-4 text-body mb-5">Busqueda de cócteles</h1>
        <div class="d-flex justify-content-center">
          <form class="form-inline" v-on:submit.prevent="buscarCoctel()">
            <input type="text" class="form-control mr-2" placeholder="Introduce el cóctel..." v-model="nombreCoctel"/>
            <button class="btn btn-primary">Buscar</button>
          </form>
        </div>
      </div>
    </div>

    <div v-if="bebidas != null">
        <div class="row">
        <div class="col-lg-8 mx-auto">
            
            <paginate  class="list-group shadow" ref="paginator" name="bebidas" :list="bebidas" :per="3">
            
            <li class="list-group-item" v-for="bebida in paginated('bebidas')" :key="bebida.idDrink">
                
                <div class="media align-items-lg-center flex-column flex-lg-row p-3" >
                <div class="media-body order-2 order-lg-1">
                    <h5 class="mt-0 font-weight-bold mb-2">{{ bebida.strDrink }}</h5>
                    <p class="font-italic text-muted mb-0 small"> {{ bebida.strCategory }} | {{ bebida.strAlcoholic }} | {{ bebida.strGlass }}</p>
                    <p>{{ bebida.strInstructions }}</p>
                </div>
                <img :src="bebida.strDrinkThumb" alt="Generic placeholder image" width="200" class="ml-lg-5 order-1 order-lg-2" />
                </div>
                
            </li>
            
            </paginate>
        
        </div>
        </div>
        <div class="d-flex justify-content-center mt-4">
            <paginate-links :classes="{ ul: 'pagination', li: 'page-item', a: 'page-link' }" for="bebidas" :show-step-links="true" :limit="2" :async="true"></paginate-links>
        </div>
    </div>
    <div v-else>
        <h2 class="display-5 text-center">Sin resultados</h2>
    </div>
  </div>
</template>

<script>
import axios from "axios";

export default {
  name: "PaginacionEnumerada",
  data() {
    return {
      bebidas: [],
      paginate: ["bebidas"],
      nombreCoctel: "",
    };
  },
  methods: {
    buscarCoctel() {
      var request = "/api/json/v1/1/search.php?s=" + this.nombreCoctel;
      var url = "https://www.thecocktaildb.com/" + request;
      axios.get(url).then((res) => {
        this.bebidas = res.data.drinks;
        console.log(this.bebidas);
      });
    },
  },
};
</script>

<style scoped>
img {
  height: 170px;
  width: 140px;
}
</style>

Recordar que para mostrar los componentes debemos de mostrarlos en nuestro App.vue.

Adicionalmente, podemos añadir esta etiqueta para que nos muestre el número de resultados:

<span v-if="$refs.paginator">
  Viewing {{$refs.paginator.pageItemsCount}} results
</span>

Hasta aquí este post, espero que os haya servido de ayuda, nos vemos en el siguiente. ¡Hasta la próxima!

Autor/a: Luis Enrique Frías Araujo

Curso: Desarrollo Web Full Stack, MultiCloud y Multiplataforma

Centro: Tajamar

Año académico: 2021-2022

GitHub: https://github.com/luisnrq/paginacion

This Post Has One Comment

  1. Batigala Reply

    Hola, como puedo cambiar el estilo de :classes=»{ ul: ‘pagination’, li: ‘page-item’, a: ‘page-link’ }
    intento en la css poner
    .page-item {
    color: #FF5224;

    }
    pero no lo toma en cuenta
    tampoco me deja ponerlo alineado al centro con text-center

Leave a Comment

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

Este sitio usa Akismet para reducir el spam. Aprende cómo se procesan los datos de tus comentarios.