Buscador de Perfiles en Diablo III: Creación de Formulario y Título
Clase 14 de 27 • Curso Avanzado de Vue.js 2
Contenido del curso
VueCli, configuración inicial del proyecto y consumo del API de Blizzard
- 2

Creación de Aplicaciones Vue.js con API de Diablo III
03:24 min - 3

Desarrollo de Aplicaciones con APIs de Blizzard: Guía Completa
04:55 min - 4

Estructura y gestión de carpetas en proyectos Vue.js
04:40 min - 5

Instalación y configuración de librerías en Vue con Bootstrap
01:29 min - 6

Configuración de Axios para llamadas a APIs de Diablo III
02:45 min - 7

Gestión de Tokens con Vuex: Integración y Almacenamiento en Vue.js
05:17 min
Creación de los componentes y layouts de nuestro proyecto
- 8

Componente Reutilizable de Carga con Vue.js
03:05 min - 9

Estilos CSS oscuros para aplicaciones Vue.js con Stylus
02:01 min - 10

Creación de Layouts con Vue y Bootstrap para Mejorar la UI
06:08 min - 11

Organización de Assets en Vue: Imágenes, Fuentes y CSS Globales
02:47 min - 12

Creación de NavBar y Footer con BootstrapVue y FontAwesome
06:25 min - 13

Refactorización de Importaciones en Vue.js con Plugins
02:16 min - 14

Buscador de Perfiles en Diablo III: Creación de Formulario y Título
Viendo ahora - 15

Rutas Dinámicas y Lazy Loading en Vue.js
08:02 min - 16

Construcción y Consumo de APIs con Vue.js y Vuex
13:51 min - 17

Creación y Uso de Componentes en Vue.js: MainBlock y TopHeroes
17:32 min - 18

Visualización de Héroes con Bootstrap-Vue en Diablo III
17:28 min - 19

Componente de Progreso de Actos en Vue.js
06:11 min - 20

Implementación de Componentes Vue: MainBlock y PlayerStats
12:55 min - 21

Navegación y Visualización de Artesanos en Vue.js
13:48 min - 22

Funciones y Componentes para la Vista de Héroe en Vue.js
27:13 min
Agregando funcionalidades avanzadas a nuestro proyecto
- 23

Carga Diferida de Componentes en Vue.js: Mejora de Rendimiento
08:01 min - 24

Implementación de Inventario de Objetos de Personaje en Vue.js
15:48 min - 25

Directivas Personalizadas en Vue: Creación y Uso Básico
07:28 min - 26

Configuración y despliegue de aplicaciones en Netlify con Vue.js
06:54 min - 27

Creación y Personalización de Páginas en Vue.js
06:31 min
Llevamos bastante tiempo trasteando con nuestro proyecto, pero apenas estamos avanzando. Hora de empezar a darle forma a nuestro buscador de perfiles de Diablo III.
Lo primero que tenemos que hacer es crear un formulario que busque el usuario según la región en la que estemos. Esto es importante ya que un usuario puede existir en una región, pero no estar en otra. Por lo tanto necesitamos los 2 parámetros:
- BattleTag o Identificador de usuario, con el formato: NombreCool#1234
- Región, que puede ser una de las siguientes: 'US', 'EU', 'KR', 'TW'. La región de CN (China) la dejamos fuera en este ejemplo, que tiene una configuración especial, distinta al resto.
Antes de empezar con el formulario vamos a poner un título grande, que le de nombre a nuestra app.
Para ello creamos, dentro de nuestra carpeta vista /Home, dos componentes: HomeForm.vue y HomeTitle.vue. Quedaría así:
📂 /views └──📂 /Home ├── Index.vue ├── HomeForm.vue └── HomeTitle.vue
Empezamos con el título, un componente bastante sencillo.
<template> <div class="home-title text-center"> <h1 class="my-5 font-diablo">Diablo 3 Profile Finder</h1> <p class="lead text-muted">Enter your <em> <a href="https://eu.battle.net/support/es/article/75767" target="_blank" title="Format: YourProfile#1234">battle-tag</a> </em> and select your region to see your profile!</p> <hr class="mt-5"> </div> </template> <script> export default { name: 'HomeTitle' } </script>
Ya estamos haciendo uso de nuestra tipografía DiabloHeavy. Mira la etiqueta <h1> y la clase que le hemos puesto. Dejamos el título centrado con un buen espaciado. Ya podemos incluirlo en nuestra Home y ver que tal queda.
Para ello, simplemente vamos a traer el componente que acabamos de crear y a modificar nuestra vista (corresponde al archivo /views/Home/Index.vue) para dejarla de esta forma:
<template> <div class="home"> <HomeTitle/> </div> </template> <script> import HomeTitle from './HomeTitle' export default { name: 'Home', components: { HomeTitle } } </script>
Tu aplicación se debería ver así:
Para el formulario, vamos al componente /Home/HomeForm.vue. Vamos a crear un formulario con 2 inputs; uno va a ser una caja de texto y el otro será un select.
En la caja de texto el usuario podrá escribir su BattleTag. En el selector, podrá elegir entre una de las regiones que le mostremos.
Necesitaremos también un botón para controlar el envío del formulario. Bootstrap nos proporciona unos buenos componentes para trabajar con formularios, que en el fondo se renderizan en etiquetas HTML válidas.
Lo bueno de esto es que al pulsar la tecla Enter de tu teclado se hará el Submit (envío) del formulario. Nos aprovecharemos de esta funcionalidad por defecto que traen los formularios de HTML para mejorar la experiencia del usuario en nuestra app web.
Por último, haciendo uso del estándar de HTML, podemos indicarle a los input de nuestro formulario que son requeridos con el atributo required. Esta será nuestra pequeña (y única) validación para nuestro proyecto. En el caso de un proyecto real, deberías validar tus formularios meticulosamente: formato, tamaño, nº caracteres, etc.
> 📗 Infórmate acerca de los atributos de un <input> de un formulario HTML en este enlace: https://developer.mozilla.org/es/docs/Web/HTML/Elemento/input
> Para la etiqueta <select>, puedes leer esto: https://developer.mozilla.org/es/docs/Web/HTML/Elemento/select
La parte del HTML de nuestro componente HomeForm.vue es la siguiente:
<template> <div class="search-form my-5"> <div class="row"> <div class="col-12 col-md-8 offset-md-2"> <!-- Formulario --> <b-form @submit.prevent="onSubmit"> <!-- Grupo 1 (Input texto) --> <b-form-group id="input-group-1" label="BattleTag:" label-for="input-text" description="Format: YourProfile#1234" > <b-form-input id="input-text" v-model="form.battleTag" type="text" size="lg" required placeholder="BattleTag" /> </b-form-group> <!-- Grupo 2 (Selector de región) --> <b-form-group id="input-group-3" label="Region:" label-for="input-region"> <b-form-select id="input-region" v-model="form.region" size="lg" :options="regions" required /> </b-form-group> <!-- Botón envío --> <div class="d-flex justify-content-end mt-5"> <b-button type="submit" variant="primary" size="lg">Submit</b-button> </div> </b-form> </div> </div> </div> </template>
En la parte de JavaScript de nuestro componente, vamos a necesitar el modelo asociado al formulario, el listado de regiones que queremos pintar en el selector de región y una función que haga algo cuando el formulario se envíe.
Por lo cual, el bloque <script> de nuestro componente quedaría así:
import { regions } from '@/utils/regions' export default { name: 'MainForm', data () { return { form: { battleTag: '', region: 'eu' } } }, computed: { regions () { return regions.map(region => ({ value: region, text: region.toUpperCase() })) } }, methods: { onSubmit () { const { region, battleTag } = this.form this.$router.push({ name: 'Profile', params: { region, battleTag: battleTag.replace('#', '-') } }) } } }
Para las regiones hemos creado una computed property o propiedad computada que nos devuelve un array de objetos con las regiones en minúscula como value y en mayúscula como texto a mostrar.
Tenemos que crear un nuevo archivo, de nombre regions.js, en la carpeta /utils para que esto funcione con el siguiente contenido:
const regions = ['us', 'eu', 'kr', 'tw'] const locales = { us: 'en_US', eu: 'en_GB', kr: 'ko_KR', tw: 'zh_TW' } export { regions, locales }
Código completo HomeForm.vue
<template> <div class="search-form my-5"> <div class="row"> <div class="col-12 col-md-8 offset-md-2"> <b-form @submit.prevent="onSubmit"> <b-form-group id="input-group-1" label="BattleTag:" label-for="input-text" description="Format: YourProfile#1234" > <b-form-input id="input-text" v-model="form.battleTag" type="text" size="lg" required placeholder="BattleTag" /> </b-form-group> <b-form-group id="input-group-3" label="Region:" label-for="input-region"> <b-form-select id="input-region" v-model="form.region" size="lg" :options="regions" required /> </b-form-group> <div class="d-flex justify-content-end mt-5"> <b-button type="submit" variant="primary" size="lg">Submit</b-button> </div> </b-form> </div> </div> </div> </template> <script> import { regions } from '@/utils/regions' export default { name: 'MainForm', data () { return { form: { battleTag: '', region: 'eu' } } }, computed: { regions () { return regions.map(region => ({ value: region, text: region.toUpperCase() })) } }, methods: { onSubmit () { const { region, battleTag } = this.form this.$router.push({ name: 'Profile', params: { region, battleTag: battleTag.replace('#', '-') } }) } } } </script>
Cuando el formulario se envía, estamos haciendo un cambio de ruta (a una que aún no existe, de nombre Profile) y le estamos pasando por parámetro (params) los valores que acabamos de recuperar del formulario.
Ya casi lo tenemos, ¡probemos si funciona!
En nuestro componente principal de la vista /Home, es decir, en /views/Home/Index.vue, traemos y usamos el componente formulario que acabamos de crear; quedaría así:
<template> <div class="home-view"> <HomeTitle/> <MainForm/> </div> </template> <script> import MainForm from './HomeForm' import HomeTitle from './HomeTitle' export default { name: 'HomeView', components: { HomeTitle, MainForm } } </script>
Se debería ver así:
Para ver si el formulario hace lo que estamos esperando que haga, necesitamos comprobar varios casos:
-
No se envía el formulario
- No escribimos nada en el input y enviamos el formulario a través del botón (submit)
- (Con el foco en el input) no escribimos nada en el formulario y le damos a la tecla Enter del teclado
Se envía el formulario

-
- Escribimos algo en el input y le damos a la tecla Enter del teclado
- Escribimos un texto en el input y le damos a enviar

¡Bravo!
El formulario está funcionando como es debido, pero tenemos un pequeño problema (de fácil solución). No tenemos la ruta Profile definida, por lo tanto Vue no sabe qué hacer en este caso.
Lo arreglaremos en las siguientes lecturas.