Progreso (Actos)

19/27

Lectura

Uno de los valores que nos devuelve la API del juego cuando le pedimos los datos de un jugador es el progreso. Esto nos indica el estado de los actos (hay cinco), es decir, si los ha completado o no.
Vamos a crear un componente, muy sencillo, que nos indique si el usuario ha completado un acto o no. Para indicar si el acto está completado o no usaremos una imagen (Sprites CSS), que estará oscurecida y con un candado cuando esté sin completar y sin el candado y bien clara cuando esté completado.

La imagen que usaremos como Sprite CSS es esta:

progress

Lo primero que vamos a hacer es crear los estilos CSS, en nuestro fichero global de CSS, /assets/main.styl. Vamos a añadir el siguiente contenido:

// ---------------------
// Acts
// ---------------------

.act
  background-image: url('../img/progress.png')
  background-size 500%

  &.act1
    &.pending
      background-position -1px 0

    &.done
      background-position -1px 57px

  &.act2
    &.pending
      background-position -51px 0

    &.done
      background-position -51px -56px

  &.act3
    &.pending
      background-position -101px 0px

    &.done
      background-position -101px -168px

  &.act4
    &.pending
      background-position -151px 0px

    &.done
      background-position -151px -168px

  &.act5
    &.pending
      background-position 50px 0

    &.done
      background-position 50px 57px

Hemos creado unas clases CSS que nos van a permitir mostrar la imagen correspondiente a cada acto y sus dos estados: pending (sin completar) y done (completado). Si queremos mostrar el acto dos completado lo que tenemos que hacer es tan sencillo como darle las clases "act act2 done".
Esto nos mostraría la porción de imagen correspondiente al acto 2 completado, que lo estamos controlando con la propiedad CSS de background-positon.

Ahora tenemos que crear los archivos y directorios que vamos a utilizar con este componente de progreso de la historia del juego. Cuando juegas a Diablo III puedes subir niveles y hacer misiones especiales sin necesidad de completar la historia del juego.

📗 Diablo 3 - Modos de juego: https://eu.diablo3.com/es/game/guide/gameplay/game-modes

Es por eso que implementamos este componente. Para ello, al mismo nivel del directorio /TopHeroes, creamos un directorio llamado /ProgressList. Dentro de este, creamos 2 ficheros: Index.vue y ProgressItem.vue.

📂 /MainBlock
└──📂 /ProgressList
   ├── Index.vue
   └── ProgressItem.vue

El objeto que vamos a usar para pintar nuestro componente tiene este formato:

{ "progression": { "act1":true, "act3":true, "act2":true, "act5":true, "act4":true } }

Fíjate que no viene ordenado por actos, por lo que vamos a tener que realizar esta tarea de ordenamiento antes de poder iterar sobre el objeto de progression.

Lo primero que vamos a hacer es usar el componente (aunque esté vacío) en el componente padre, es decir, en /MainBlock/Index.vue. Los 3 pasos de siempre. Importar, habilitar, utilizar.

// MainBlock/Index.vue

// ...
import ProgressList from './ProgressList/Index'

export default {
  name: 'MainBlock',
  components: { ProgressList, HeroesList, TopHeroes }
  // ...
}

Para usarlo, debajo del componente HeroesList, agregamos lo siguiente:

<div class="grid-item item-left">
  <TopHeroes v-if="hasHeroes" :heroes="topHeroes"/>

  <HeroesList v-if="hasHeroesList" :heroes="heroesList"/>

  <ProgressList :acts="profileData.progression"/>
</div>

Al abrir la consola del navegador, es normal que veas errores o que la app no te funcione. Lo iremos corrigiendo a medida que vayamos avanzando.


Empezamos con el componente principal, es decir, con /ProgressList/Index.vue:

<template>
  <div class="progression-bosses pt-4 mt-5 border-top">
    <h2 class="font-diablo mb-4">Progression</h2>
    <b-row>
      <b-col v-for="(val, key) in sortedActs" :key="key" class="col-12 col-md-2">
        <div class="bg-dark rounded mb-2">
          <ProgressItem :act="{actNum: key, value: val}"/>
        </div>
      </b-col>
    </b-row>
  </div>
</template>

<script>
import ProgressItem from './ProgressItem'

export default {
  name: 'ProgressBosses',
  components: { ProgressItem },
  props: {
    acts: {
      required: true,
      type: Object
    }
  },
  computed: {
    /**
       * Order acts from 1 to 5
       * @returns {Object} Ordered acts
       */
    sortedActs () {
      return Object.keys(this.acts)
        .sort()
        .reduce((a, c) => {
          a[c] = this.acts[c]
          return a
        }, {})
    }
  }
}
</script>

<style lang="stylus">
  .progression-bosses
    .boss-img
      display block

      .act
        margin 0 auto
        width 50px
        height 55px
</style>

Todo lo que tiene este componente no requiere explicación, puesto que es un componente muy sencillo.
A modo de resumen este componente tiene definidas una prop, que son los actos, que los ordenamos a través de la función sortedActs (aunque en realidad es una computed property).
En el HTML iteramos sobre este objeto que contiene los actos ordenados del uno al cinco y cada elemento corresponde a otro componente (ProgressItem, que vamos a ver ahora) que recibe como parámetro un objeto con el acto (ej. act2) y el valor (ej. true).

El componente ProgressItem.vue tiene el siguiente contenido:

<template>
  <div class="d-flex flex-column" :title="actTitle">
    <div class="boss-img pt-2">
      <div class="act" :class="actClass"></div>
    </div>
    <p class="d-block text-center m-0 lead font-weight-bold">{{ fullActName }}</p>
  </div>
</template>

<script>
const acts = {
  act1: 'I',
  act2: 'II',
  act3: 'III',
  act4: 'IV',
  act5: 'V'
}

export default {
  name: 'ProgressItem',
  props: {
    act: {
      required: true,
      type: Object,
      validator: (obj) => {
        return Object.keys(obj).length === 2
      }
    }
  },
  computed: {
    fullActName () {
      return `Act ${acts[this.act.actNum]}`
    },
    actClass () {
      const status = this.act.value ? 'done' : 'pending'
      return `${this.act.actNum} ${status}`
    },
    actTitle () {
      return this.act.value
        ? 'Act completed! 💃'
        : 'Act uncompleted 🙈'
    }
  }
}
</script>

Aunque este componente es bastante sencillo, vamos a comentar un par de cosas:

  • La prop act tiene una función de validación distinta a las que hemos visto anteriormente. No es gran cosa, pero está comprobando que el numero de claves del objeto que recibe sea igual a 2. Muy simple.

  • La computed property actTitle nos devuelve un String dependiendo del valor del acto, es decir, si está completado o no. Para poder ver este texto, deberías dejar el ratón encima de dicho elemento unos segundos.
    Lo diferencial de esto es que estamos incluyendo emojis (íconos) en el texto. ¡Sí! Los emojis los podemos usar como texto normal, usando las comillas, como si de un texto se tratara. 🤘😏🤘

📗 No soy muy fan de W3Schools, pero en este caso podemos hacer una excepción. Explicación de los emojis en la web: https://www.w3schools.com/html/html_emojis.asp

Exceptuando un par de cosas, estos componentes que acabamos de crear no tenían complejidad alguna. Si has seguido todos los pasos correctamente, la app debería verse así:

preview-1.pngModificando los valores desde las Vue DevTools en el navegador, para ver ambos estados en acción:

preview-2.png

Y esto sería todo. Ahora vamos a empezar con el bloque de la derecha de nuestro grid, donde trabajaremos con los stats del usuario y el tiempo jugado por héroe.
Quédate con lo de los emojis en mente, pues los volveremos a utilizar más adelante.

Aportes 7

Preguntas 0

Ordenar por:

¿Quieres ver más aportes, preguntas y respuestas de la comunidad? Crea una cuenta o inicia sesión.

Recuerden quitar el atributo “Scoped” (Aislar solamente a este componente) de la parte de CSS del Componente ProgressList/Index.vue, ya que al contener las clases que utilizaremos para su hijo ProgressItem.vue necesitamos que los los estilos puedan “salir” desde este componente 👍🏻

A la clase .act en main.styl falta añadir:

.act 
	...
	width 50px
	height 55px
	margin 0 auto
	...

Esta clase fue cortita y básica, me gusta, con las otras clases me llevé una hora aproximadamente leyendo y entendiendo bien todo jaja, aunque no comprendo muy bien a que se refería con la parte de que los actos no estaban ordenados, es decir, yo los veo ordenados D:

Jorge, viendo que los componentes es lo que mas abunda, casi todo lo podemos volver un componente, ¿Que criterios tomas y/o recomiendas para decidir si algo lo pasas a un componente por separado?

Estuve buscando el error de por que las imagenes se veian blancas y era por que tenia el modo oscuro de mi navegador activado 😄

¿Como se cambia el valor al act de true a false con las Vue DevTools?

A alguien le quedaron los estilos asi?