Introducción

Bien, en capítulos anteriores vimos qué son y cómo crear componentes. Pues bien, en el día de hoy vamos a ver todo lo que puede ofrecer Vue respecto al sistema de vistas de los componentes.

Antes de nada tiene que saber que en las vistas de Vue (además de en la lógica del componente) también puedes crear bucles, condicionales, etc, como cualquier lenguaje de programación. Pero lo primero es ver cómo se pueden crear variables en los componentes para poder pintarlas en la vista.

Sistema de vistas de Vue

Cómo crear variables en Vue

Hay dos formas de crear variables en los componentes o más bien dos sintaxis para crearlas, vamos a ver las dos, aunque realmente sirven para lo mismo:

export default {
  data: function() {
    return {
      miVariable: "Hola mundo"
    }
  }
}

Si, al principio puede resultar un poco extraño tener que declarar una propiedad data que en realidad es una función que devuelve un objeto con las variables, pero Vue es así y hay que aconstumbrarse.

Todas las variables que quieras usar en la vista las tienes que declarar aquí y además tienen que tener un valor inicial. Mi recomendación es que las variables tengan un nombre descriptivo y que las declares en formato camelCase (la primera letra minúscula y cada palabra con la primera letra en mayúscula).

Otra forma de declarar las variables en Vue, y que yo utilizo más porque hay que escribir menos, es la siguiente:

export default {
  data: () => ({
    miVariable: "Hola mundo"
  })
}

Esta forma de declarar variables sirve para lo mismo que lo anterior y funciona de la misma manera, solo cambia la sintaxis.

Otra cosa a tener en cuenta de las variables, es que como hemos dicho antes, para que las puedas usar en la vista tienen que estar declaradas en esta sección, por lo tanto si quieres importar un JSON, por ejemplo, o variables de otro fichero, lo tienes que hacer así:

import data from "@/data/data.js"

export default {
  data: () => ({
    miVariable: data
  })
}

Una vez que esté declarada en la sección data ya la puedes usar para mostrar cosas en la vista.

¿Y para pintar una variable en la vista cómo se hace? Pues lo puedes hacer con la sintaxis de moustache, siempre y cuando estés en el mismo componente claro, ya que por el momento no se pueden pasar variables de unos componentes a otros (más adelante veremos cómo).

<template>
  <div class="content">
    {{miVariable}}
  </div>
</template>

<script>
export default {
  data: () => ({
    miVariable: "Hola mundo"
  })
}
</script>

Lo bueno de Vue es que todas las variables del data son reactivas. Eso significa que Vue, en caso de que la variable cambie de valor, es capaz de actualizar el nuevo valor en la vista sin que tengas que hacer nada.

Por cierto, el valor de una variable de momento no lo puedes declarar a partir de otro, es decir esto NO se puede hacer:

data: () => ({
  single: 1,
  double: single * 2
})

Más adelante veremos como resolver esta situación.

Condicionales con v-if

Dentro de la vista también podemos tener cierta lógica, por ejemplo con el v-if puedes hacer que ciertos elementos se muestren o no dependiendo de el valor de una variable. Pongamos un ejemplo:

<template>
  <div class="content">
    <p v-if="condition">Este mensaje no se va a mostrar</p>
    <p>Este mensaje si que se va a mostrar</p>
  </div>
</template>

<script>
export default {
  data: () => ({
    condition: false
  })
};
</script>

<style scoped>
</style>

En este caso como el valor de la variable condition lo hemos establecido a falso, el primer mensaje no se mostrará, en cambio el segundo valor si que se mostrará. El v-if se puede aplicar a cualquier elemento html, es decir, lo puedes poner en un h1 o en un img o incluso dentro de la etiqueta de otro componente: <mi-componente v-if="condition">.

Es importante saber que si aplicas el v-if a un elemento HTML, se aplicará a todo el elemento, incluso a su contenido. Por ejemplo en el caso de abajo se ocultará toda la lista:

<template>
  <div class="content">
    <ul v-if="condition">
      <li>Todo este elemento no se va a mostrar</li>
      <li>Todo lo que haya dentro de la lista no se muestra</li>
    </ul>
    <p>Este mensaje si que se va a mostrar</p>
  </div>
</template>

Los v-if también los puedes negar, puedes poner v-else o v-else-if para anidar e incluso puedes crear condiciones más complejas con operadores and y or. Básicamente funciona como un if de un lenguaje de programación normal. Veamos más ejemplos:

<template>
  <div class="content">
    <ul v-if="condition">
      <li>Todo este elemento no se va a mostrar</li>
      <li>Todo lo que haya dentro de la lista no se muestra</li>
    </ul>
    <p v-else-if="list.length !== 0 && list[0] === 0">
      Este mensaje si se muestra
    </p>
    <p v-else>
      Este mensaje no se muestra porque se cumple la condición
    </p>
  </div>
</template>

<script>
export default {
  data: () => ({
    condition: false,
    list: [0,2,3,4,5]
  })
};
</script>

<style scoped>
</style>

En este componente solo se mostrará el mensaje del medio. En este ejemplo he creado una lista dentro del data. Básicamente puedes crear cualquier variable javascript dentro del data. Cada variable se separá entre sí con una coma.

v-show. Diferencias con el v-if

Diferencias con el v-if

El v-show en Vue funciona muy parecido a como lo hace el v-if, pero tiene algunas diferencias. Para empezar, dentro de la condición del v-show puedes colocar todo lo que podías colocar dentro del v-if, por ejemplo:

<template>
  <div class="content">
    <p v-show="condition">Este mensaje no se va a mostrar</p>
    <p>Este mensaje si que se va a mostrar</p>
  </div>
</template>

<script>
export default {
  data: () => ({
    condition: false
  })
};
</script>

<style scoped>
</style>

El v-show también permitirá o no mostrar un elemento del html pero hay una diferencia fundamental con el v-if.

En el v-if cuando no se muestra un elemento Vue lo elimina directamente del DOM, es decir, elimina toda la etiqueta HTML y la muestra cuando la necesita. El v-show no elimina la etiqueta html, la oculta. Lo que hace el v-show es añadir display:none al elemento para que no se muestre, pero sigue estando en los dentro del DOM.

Otra diferencia fundamental con el v-if es que no puedes hacer v-else con lo cual está más limitado en ese aspecto.

En general yo suelo usar v-show antes que v-if cuando necesito sí o sí que el elemento no se elimine del html de la página y solo permanezca oculto cargado en el DOM.

Bucles for con v-for

Como en muchos lenguajes de programación, en las vistas de Vue también podemos tener bucles, en este caso para pintar varios elementos en el HTML. Vamos a verlo con un ejemplo:

<template>
  <ul class="list">
    <li v-for="(item, i) in elements" :key="i">
    ID: {{item.id}} - {{item.name}}
    </li>
  </ul>
</template>

<script>
export default {
  data: () => ({
    elements: [
      { name: "Elemento 1", id: 1 },
      { name: "Elemento 2", id: 2 },
      { name: "Elemento 3", id: 3 }
    ]
  })
};
</script>

<style scoped>
</style>

Pintar una lista en Vue

En este ejemplo lo que hago es declarar una variable llamada elemets inicializada con un array de objetos. En la vista lo que hago es crear una lista <ul> y dentro cada uno de los items con un v-for para que se cree un loop y se pinten.

Dentro del v-for lo que hago es recorrer el array de objetos, en este caso entre paréntesis pongo (item, i). Estos son los nombres que yo he decidido para estas variables, pero tu puedes poner los que quieras. Veamos qué se guarda en las variables:

  • “item” es el nombre que le he puesto a la variable que contendrá cada uno de los items, a medida que avanza el bucle este valor va cambiando para que lo puedas pintar.
  • “i” es el nombre que le he puesto a la variable contador, es decir, en cada paso del bucle esta variable contendrá el número del item que se está pintando, es decir, para el primer elemento “i” vale 0, para el segundo vale 1 etc.

Otro detalle a tener en cuenta en los bucles es la key. Vue recomienda que siempre con el bucle for se utilice una key que sea única para cada item del bucle. Lo que hago es crear la key con el valor de la variable “i” del contador para que cada item tenga una key única. Esto sirve para que Vue pueda identificar correctamente cada item del bucle. :key="i"

Por último dentro de cada <li> meto con la notación punto cada propiedad de cada item que quiero pintar (id y name).

Si abres la página con este ejemplo podrás ver que se crea una lista que pinta cada uno de los elementos definidos dentro del array elements. Si modificas el array y metes nuevos objetos verás que se añaden sin tener que crear nuevos <li>. Es decir el bucle for duplicará la etiqueta HTML sobre la que esté declarado (li en este ejemplo) por cada una de las iteracciones del bucle.

Pero cuidado porque en la vista hemos dicho que pinte el id y el name de los arrays y si metes elementos en el array que no tengan estas propiedades no se pintarán.

Como podrás suponer, los v-for también se pueden anidar:

<template>
  <ul class="list">
    <li v-for="(item, i) in elements" :key="i">
      ID: {{item.id}} - {{item.name}} | childrens: 
      <span v-for="(children, j) in item.childrens" :key="'child' + j">
        {{children}}, 
      </span>
    </li>
  </ul>
</template>

<script>
export default {
  data: () => ({
    elements: [
      { name: "Elemento 1", id: 1, childrens: [1,3,4] },
      { name: "Elemento 2", id: 2, childrens: [3,5,5] },
      { name: "Elemento 3", id: 3, childrens: [5,7,3] }
    ]
  })
};
</script>

<style scoped>
</style>

Aquí para el segundo bucle he decidido crear la key con la unión de un string ‘child’ y el contador del segundo array para que se único para cada hijo y no coincida con los del padre.

Propiedades de las etiquetas html dinámicas

Otra de las cosas muy interesantes que ofrece Vue para las vistas es la posibilidad de poner cada una de las propiedades de las etiquetas html como propiedades dinámicas, es decir, como propiedades con valor de la lógica del componente, por ejemplo:

<template>
  <div class="content">
    <img :src="source" />
  </div>
</template>

<script>
export default {
  data: () => ({
    source: "https://i.imgur.com/BBcy6Wc.jpg"
  })
};
</script>

<style scoped>
</style>

Aquí hay que tener en cuenta una cosa muy importante. Para que la propiedad sea dinámica y Vue la pueda coger de la lógica del componente, tiene que estar precedida por dos puntos :

Dentro del la propiedad puedes escribir el nombre de la variable que quieres que coja.

Esto se puede hacer con cualquier propiedad de las nativas de HTML, por ejemplo:

<template>
  <div class="content">
    <img :src="source" :class="myClass" />
  </div>
</template>

<script>
export default {
  data: () => ({
    source: "https://i.imgur.com/BBcy6Wc.jpg",
    myClass: "my-class"
  })
};
</script>

<style scoped>
</style>

Si por ejemplo no pongo los dos puntos antes de la clase, la clase que tendría en la página sería myClass literalmente y no la variable que queremos que coja.

Por cierto, cuando quieras meter dentro de una de estas etiquetas dinámicas un string, lo tienes que hacer con comillas simples: '

<img :src="source" :class="myClass + '-active'" />

Clases y estilos inline dinámicos

Como acabamos de ver, puedes crear clases que provengan de variables en la lógica del componente, pero todavía se pueden hacer más cosas con las clases y los estilos:

<template>
  <div class="content">
    <img :src="source" :class="classObject" />
  </div>
</template>

<script>
export default {
  data: () => ({
    source: "https://i.imgur.com/BBcy6Wc.jpg",
      classObject: {
      active: true,
      "text-danger": false
    }
  })
};
</script>

<style scoped>
</style>

En este caso el valor de la clase es un objeto y no un string. Dentro del objeto como propiedad pones el valor que quieres que tenga y true o false para decidir si se usa esa clase o no. Más adelante veremos como actualizar estos valores para que tenga sentido usar esta notación.

Si te fijas el nombre de la segunda clase está entre comillas, esto se hace para que se pueda usar el guión, de lo contrario salta error porque no se puede crear una propiedad en javascript con guión.

También puedes crear estos objetos directamente en la vista:

<template>
  <div class="content">
    <img :src="source" :class="{active: isActive, danger: isDanger} " />
  </div>
</template>

<script>
export default {
  data: () => ({
    source: "https://i.imgur.com/BBcy6Wc.jpg",
    isActive: true,
    isDanger: false
  })
};
</script>

<style scoped>
</style>

De la misma manera que con las clases, también podemos crear estilos inline que vengan de la lógica del componente:

<template>
  <div class="content">
    <div :style="styleObject"></div>
  </div>
</template>

<script>
export default {
  data: () => ({
    source: "https://i.imgur.com/BBcy6Wc.jpg",
    styleObject: {
      background: "red",
      width: "300px",
      height: "30px",
      fontSize: "13px"
    }
  })
};
</script>

<style scoped>
</style>

Como puedes ver, cuando necesitas meter un estilo que tiene un nombre con guión, como por ejemplo, font-size, lo tienes que meter en camelCase para que Vue lo cambie por el nombre correcto

Como antes, también los puedes meter directamente en la vista si lo prefieres:

<template>
  <div class="content">
    <div :style="{width: '200px', height: '40px', background: 'blue'}"></div>
  </div>
</template>

<script>
export default {
  data: () => ({
    source: "https://i.imgur.com/BBcy6Wc.jpg"
  })
};
</script>

<style scoped>
</style>

Por cierto y para acabar, también puedes pasar un array a los estilos para usar varios objetos:

<div :style="[baseStyles, overridingStyles]"></div>

En este caso las propiedades que tenga overridingStyles y que también tenga baseStyles serán sobreescritas y las demás mergeadas.

Conclusiones

El sistema de vistas de Vue es bastante simple, pero a la vez es muy flexible y permite hacer cosas muy complejas que veremos más adelante.

Hoy hemos visto todo lo referente a las vistas, pero todavía no tenemos nada dinámico, solo sabemos pintar cosas y poco más. En el siguiente capítulo empezaremos a crear componentes dinámicos de verdad, crearemos métodos, cierta lógica con las variables, etc.