Programación usando VueJS (Directivas, eventos, etc…). Parte 2

Manipulando el DOM

Si queremos manipular el DOM, VueJS nos ofrece mecanismos para que esa tarea se pueda realizar de una forma sencilla.

El primero de los mecanismos que nos ofrece VueJS son las expresiones.

Las expresiones son los parámetros que se ponen entre las llaves {{ mensaje }}  y que nos permiten representar en pantalla los valores de nuestro modelo.

A continuación añadiré algún ejemplo de expresiones que se usan en VueJS.

<template>
  <div id="app">
    <img src="./assets/logo.png">
    <h1>Expresiones</h1>
    <p>Imprime la propiedad ---> {{ mensaje }}</p>
    <p>Suma de 2 + 2 en la expresión ---> {{ 2 + 2 }}</p>
    <p>Multiplicación de 2 * 2 en la expresión ---> {{ 2 * 2 }}</p>
    <p>Concatenando cadena de texto ---> {{ 'Hola' + ' mundo' }}</p>
    <p>Acceso a las propiedades de un objeto ---> {{ datos.latitude }}</p>
    <p>Ejecutando métodos de Javascript ---> {{ Math.floor(Math.random() * 10) }}</p>
  </div>
</template>

<script>
export default {
  name: 'app',
  data () {
    return {
      mensaje: 'Hola mundo VueJS',
      datos: {
        latitude: 3.44343212,
        longitude: 40.1213433
      }
    }
  }
}
</script>

<style lang="scss">
#app {
  font-family: 'Avenir', Helvetica, Arial, sans-serif;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  text-align: center;
  color: #2c3e50;
  margin-top: 60px;
}
h1, h2 {
  font-weight: normal;
}
</style>

El siguiente mecanismo que nos ofrece VueJS son las directivas.

Las directivas (v-if, v-else, v-for, etc…) son atributos que podemos agregar a nuestros elementos HTML y nos sirven para aplicar transformaciones en ellos mismos.

<template>
  <div id="app">
    <img src="./assets/logo.png">
    <h1>Expresiones</h1>
    <p>Imprime la propiedad ---> {{ mensaje }}</p>
    <p>Suma de 2 + 2 en la expresión ---> {{ 2 + 2 }}</p>
    <p>Multiplicación de 2 * 2 en la expresión ---> {{ 2 * 2 }}</p>
    <p>Concatenando cadena de texto ---> {{ 'Hola' + ' mundo' }}</p>
    <p>Acceso a las propiedades de un objeto ---> {{ datos.latitude }}</p>
    <p>Ejecutando métodos de Javascript ---> {{ Math.floor(Math.random() * 10) }}</p>
    <h1>Directivas</h1>
    <p>Mostrar u ocultar contenido <b>(v-show)</b> (Display: none)<span v-show="mostrar">Mostrar</span><span v-show="!mostrar">Ocultar</span></p>
    <p>Mostrar u ocultar contenido <b>(v-if, v-else, v-elseif)</b> (No existe en el DOM)<span v-if="mostrar">Mostrar</span><span v-else>Ocultar</span></p>
    <p>Bucle <b>(v-for)</b><ul><li v-for="(dia, index) in dias" v-bind:key="index">{{dia}}</li></ul></p>
    <p>Mostrar contenido <b>v-text</b> --> <span v-text="contenidoPLAIN"></span></p>
    <p>Mostrar contenido <b>v-html</b> --> <span v-html="contenidoHTML"></span></p>
  </div>
</template>

<script>
export default {
  name: 'app',
  data () {
    return {
      mensaje: 'Hola mundo VueJS',
      datos: {
        latitude: 3.44343212,
        longitude: 40.1213433
      },
      mostrar: true,
      dias: [
        'Lunes', 'Martes', 'Miercoles', 'Jueves', 'Viernes', 'Sabado', 'Domingo'
      ],
      contenidoHTML: '<h1>v-html</h1>',
      contenidoPLAIN: 'v-text'
    }
  }
}
</script>

<style lang="scss">
#app {
  font-family: 'Avenir', Helvetica, Arial, sans-serif;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  text-align: center;
  color: #2c3e50;
  margin-top: 60px;
}
h1, h2 {
  font-weight: normal;
}
</style>

A continuación un listado de las directivas que ofrece VueJS:

  • v-text: Esta directiva actualiza el contenido entero del elemento donde se aplica. Si deseamos solo modificar parte del contenido usaremos una expresión {{ propiedad }}
  • v-html: Actualiza el elemento innerHTML.
  • v-show: Muestra u oculta el contenido donde se use la directiva usando la propiedad display de CSS.
  • v-if, v-elseif, v-else: Añade a nuestro o no en base a la condición. Funciona como v-show pero esta directiva no añade el contenido al DOM.
  • v-for: Realiza un bucle.
  • v-on: Añade un listener al elemento. Se puede usar la forma abreviada usando la arroba @.
  • v-bind: Realiza un bindeo dinámico a un atributo o propiedad. También tiene su forma abreviada usando los dos puntos :
  • v-model: Con esta directiva podemos realizar un bindeo en dos direcciones, de la vista al modelo y del modelo a la vista.
  • v-pre: Con esta directiva no se representa el contenido entre las llaves {{ }}
  • v-cloak: Esta directiva permanece en el elemento hasta que la instancia de Vue asociada termine la compilación. Combinada con las reglas de CSS [v-cloak] {display: none}, podemos ocultar todas las expresiones que están entre {{}} hasta que la instancia de Vue esté lista.
  • v-once: El contenido solo se pinta una vez, aunque cambiemos el modelo ese contenido no cambiará.

El tercero de los mecanismos que ofrece VueJS es el data binding.

El data binding significa que podemos enlazar los datos desde la vista al código y viceversa.

Para ello tenemos las siguientes directivas:

  • v-bind: Bindeo en una dirección, desde el modelo hacia la vista.
  • v-model: Bindeo en dos direcciones, de modelo a vista y de vista a modelo.

Con este mecanismo conseguimos que cualquier modificación sobre el código se refleje automáticamente en la vista y si cambia la vista automáticamente cambie el código, y todo ello gracias al concepto de la reactividad.

<template>
  <div id="app">
    <img src="./assets/logo.png">
    <hr>
    <h1>Expresiones</h1>
    <p>Imprime la propiedad ---> {{ mensaje }}</p>
    <p>Suma de 2 + 2 en la expresión ---> {{ 2 + 2 }}</p>
    <p>Multiplicación de 2 * 2 en la expresión ---> {{ 2 * 2 }}</p>
    <p>Concatenando cadena de texto ---> {{ 'Hola' + ' mundo' }}</p>
    <p>Acceso a las propiedades de un objeto ---> {{ datos.latitude }}</p>
    <p>Ejecutando métodos de Javascript ---> {{ Math.floor(Math.random() * 10) }}</p>
    <hr>
    <h1>Directivas</h1>
    <p>Mostrar u ocultar contenido <b>(v-show)</b> (Display: none)<span v-show="mostrar">Mostrar</span><span v-show="!mostrar">Ocultar</span></p>
    <p>Mostrar u ocultar contenido <b>(v-if, v-else, v-elseif)</b> (No existe en el DOM)<span v-if="mostrar">Mostrar</span><span v-else>Ocultar</span></p>
    <p>Bucle <b>(v-for)</b><ul><li v-for="(dia, index) in dias" v-bind:key="index">{{dia}}</li></ul></p>
    <p>Mostrar contenido <b>v-text</b> --> <span v-text="contenidoPLAIN"></span></p>
    <p>Mostrar contenido <b>v-html</b> --> <span v-html="contenidoHTML"></span></p>
    <hr>
    <h1>Data binding</h1>
    <p><span>Descripción</span><input type="text" v-model="descripcion">Descripción: <b>v-model --> </b> {{descripcion}}</p>
    <p><span v-bind:class="colores[Math.floor(Math.random() * 2)]">Texto de cambia de color <b>v-bind:class</b></span></p>
  </div>
</template>

<script>
export default {
  name: 'app',
  data () {
    return {
      mensaje: 'Hola mundo VueJS',
      datos: {
        latitude: 3.44343212,
        longitude: 40.1213433
      },
      mostrar: true,
      dias: [
        'Lunes', 'Martes', 'Miercoles', 'Jueves', 'Viernes', 'Sabado', 'Domingo'
      ],
      contenidoHTML: '<h1>v-html</h1>',
      contenidoPLAIN: 'v-text',
      descripcion: '',
      colores: ['red', 'blue', 'green']
    }
  }
}
</script>

<style lang="scss">
.red {
  color: red;
}
.green {
  color: green;
}
.blue {
  color: blue;
}
#app {
  font-family: 'Avenir', Helvetica, Arial, sans-serif;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  text-align: center;
  color: #2c3e50;
  margin-top: 60px;
}
h1, h2 {
  font-weight: normal;
}
</style>

Continuemos ahora con las computed properties. Las computed properties son propiedades dinámicas que se calculan a partir de los valores de otras propiedades.

Para declararlas debemos crear un nuevo bloque de código llamado computed, y allí dentro definir los métodos (computed properties) con el código que necesitemos.

<template>
  <div id="app">
    <img src="./assets/logo.png">
    <hr>
    <h1>Expresiones</h1>
    <p>Imprime la propiedad ---> {{ mensaje }}</p>
    <p>Suma de 2 + 2 en la expresión ---> {{ 2 + 2 }}</p>
    <p>Multiplicación de 2 * 2 en la expresión ---> {{ 2 * 2 }}</p>
    <p>Concatenando cadena de texto ---> {{ 'Hola' + ' mundo' }}</p>
    <p>Acceso a las propiedades de un objeto ---> {{ datos.latitude }}</p>
    <p>Ejecutando métodos de Javascript ---> {{ Math.floor(Math.random() * 10) }}</p>
    <hr>
    <h1>Directivas</h1>
    <p>Mostrar u ocultar contenido <b>(v-show)</b> (Display: none)<span v-show="mostrar">Mostrar</span><span v-show="!mostrar">Ocultar</span></p>
    <p>Mostrar u ocultar contenido <b>(v-if, v-else, v-elseif)</b> (No existe en el DOM)<span v-if="mostrar">Mostrar</span><span v-else>Ocultar</span></p>
    <p>Bucle <b>(v-for)</b><ul><li v-for="(dia, index) in dias" v-bind:key="index">{{dia}}</li></ul></p>
    <p>Mostrar contenido <b>v-text</b> --> <span v-text="contenidoPLAIN"></span></p>
    <p>Mostrar contenido <b>v-html</b> --> <span v-html="contenidoHTML"></span></p>
    <hr>
    <h1>Data binding</h1>
    <p><span>Descripción</span><input type="text" v-model="descripcion">Descripción: <b>v-model --> </b> {{descripcion}}</p>
    <p><span v-bind:class="colores[Math.floor(Math.random() * 2)]">Texto de cambia de color <b>v-bind:class</b></span></p>
    <hr>
    <h1>Computed properties</h1>
    <p><span>Precio</span><input type="number" v-model="precio"> --> IVA (21%) {{ calcularEdad }}</p>
  </div>
</template>

<script>
export default {
  name: 'app',
  data () {
    return {
      mensaje: 'Hola mundo VueJS',
      datos: {
        latitude: 3.44343212,
        longitude: 40.1213433
      },
      mostrar: true,
      dias: [
        'Lunes', 'Martes', 'Miercoles', 'Jueves', 'Viernes', 'Sabado', 'Domingo'
      ],
      contenidoHTML: '<h1>v-html</h1>',
      contenidoPLAIN: 'v-text',
      descripcion: '',
      colores: ['red', 'blue', 'green'],
      precio: 10
    }
  },
  computed: {
    calcularEdad () {
      let p = parseFloat(this.precio * 0.21)
      return p
    }
  }
}
</script>

<style lang="scss">
.red {
  color: red;
}
.green {
  color: green;
}
.blue {
  color: blue;
}
#app {
  font-family: 'Avenir', Helvetica, Arial, sans-serif;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  text-align: center;
  color: #2c3e50;
  margin-top: 60px;
}
h1, h2 {
  font-weight: normal;
}
</style>

Otro de los mecanismos que ofrece VueJS son los watchers. Los watchers nos permiten ejecutar código a partir de que una propiedad de nuestra vista o modelo que cambia.

Sabiendo lo que son las computed properties deberíamos pensar que son iguales que los watchers, pero no lo son.

A continuación una breve definición de watcher computed propeties:

  • Computed properties: Son funciones que generan nuevas propiedades del componente en base a otras propiedades.
  • Watchers: No devuelven un valor, no son propiedades y tampoco podemos usarlas en las propiedades

Para poder declarar watchers, debemos crear otro bloque como hicimos en las computed llamado watch.

Dentro de ese bloque definiremos los métodos con el mismo nombre de la propiedad que deseamos observar, y usando como parámetros los valores nuevos y anterior.

<template>
  <div id="app">
    <img src="./assets/logo.png">
    <hr>
    <h1>Expresiones</h1>
    <p>Imprime la propiedad ---> {{ mensaje }}</p>
    <p>Suma de 2 + 2 en la expresión ---> {{ 2 + 2 }}</p>
    <p>Multiplicación de 2 * 2 en la expresión ---> {{ 2 * 2 }}</p>
    <p>Concatenando cadena de texto ---> {{ 'Hola' + ' mundo' }}</p>
    <p>Acceso a las propiedades de un objeto ---> {{ datos.latitude }}</p>
    <p>Ejecutando métodos de Javascript ---> {{ Math.floor(Math.random() * 10) }}</p>
    <hr>
    <h1>Directivas</h1>
    <p>Mostrar u ocultar contenido <b>(v-show)</b> (Display: none)<span v-show="mostrar">Mostrar</span><span v-show="!mostrar">Ocultar</span></p>
    <p>Mostrar u ocultar contenido <b>(v-if, v-else, v-elseif)</b> (No existe en el DOM)<span v-if="mostrar">Mostrar</span><span v-else>Ocultar</span></p>
    <p>Bucle <b>(v-for)</b><ul><li v-for="(dia, index) in dias" v-bind:key="index">{{dia}}</li></ul></p>
    <p>Mostrar contenido <b>v-text</b> --> <span v-text="contenidoPLAIN"></span></p>
    <p>Mostrar contenido <b>v-html</b> --> <span v-html="contenidoHTML"></span></p>
    <hr>
    <h1>Data binding</h1>
    <p><span>Descripción</span><input type="text" v-model="descripcion">Descripción: <b>v-model --> </b> {{descripcion}}</p>
    <p><span v-bind:class="colores[Math.floor(Math.random() * 2)]">Texto de cambia de color <b>v-bind:class</b></span></p>
    <hr>
    <h1>Computed properties</h1>
    <p><span>Precio</span><input type="number" v-model="precio"> --> IVA (21%) {{ calcularEdad }}</p>
    <h1>Watchers</h1>
    <p>Descripcion<input type="text" v-model="descripcion">{{descripcion}}</p>
  </div>
</template>

<script>
export default {
  name: 'app',
  data () {
    return {
      mensaje: 'Hola mundo VueJS',
      datos: {
        latitude: 3.44343212,
        longitude: 40.1213433
      },
      mostrar: true,
      dias: [
        'Lunes', 'Martes', 'Miercoles', 'Jueves', 'Viernes', 'Sabado', 'Domingo'
      ],
      contenidoHTML: '<h1>v-html</h1>',
      contenidoPLAIN: 'v-text',
      descripcion: '',
      colores: ['red', 'blue', 'green'],
      precio: 10
    }
  },
  computed: {
    calcularEdad () {
      let p = parseFloat(this.precio * 0.21)
      return p
    }
  },
  watch: {
    descripcion (valorNuevo, valorAnterior) {
      console.log(valorNuevo, valorAnterior)
    }
  }
}
</script>

<style lang="scss">
.red {
  color: red;
}
.green {
  color: green;
}
.blue {
  color: blue;
}
#app {
  font-family: 'Avenir', Helvetica, Arial, sans-serif;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  text-align: center;
  color: #2c3e50;
  margin-top: 60px;
}
h1, h2 {
  font-weight: normal;
}
</style>

Para finalizar vamos a ver el último de los mecanismos que nos ofrece VueJS, los eventos.

Los eventos es una de las formas que tenemos en VueJS para interactuar con nuestra aplicación.

Para definir eventos necesitamos crear un bloque nuevo llamado methods, y sera donde definiremos todos los métodos que vamos a usar.

Una cosa que tenemos que tener en cuenta es que dentro del bloque methods se definen todos los métodos que vamos a usar, ya sean mediante un evento (click, mouseover, etc..) o no.

Como en otras directivas de VueJS, la directiva v-on también tiene su forma abreviada usando la @.

<template>
  <div id="app">
    <img src="./assets/logo.png">
    <hr>
    <h1>Expresiones</h1>
    <p>Imprime la propiedad ---> {{ mensaje }}</p>
    <p>Suma de 2 + 2 en la expresión ---> {{ 2 + 2 }}</p>
    <p>Multiplicación de 2 * 2 en la expresión ---> {{ 2 * 2 }}</p>
    <p>Concatenando cadena de texto ---> {{ 'Hola' + ' mundo' }}</p>
    <p>Acceso a las propiedades de un objeto ---> {{ datos.latitude }}</p>
    <p>Ejecutando métodos de Javascript ---> {{ Math.floor(Math.random() * 10) }}</p>
    <hr>
    <h1>Directivas</h1>
    <p>Mostrar u ocultar contenido <b>(v-show)</b> (Display: none)<span v-show="mostrar">Mostrar</span><span v-show="!mostrar">Ocultar</span></p>
    <p>Mostrar u ocultar contenido <b>(v-if, v-else, v-elseif)</b> (No existe en el DOM)<span v-if="mostrar">Mostrar</span><span v-else>Ocultar</span></p>
    <p>Bucle <b>(v-for)</b><ul><li v-for="(dia, index) in dias" v-bind:key="index">{{dia}}</li></ul></p>
    <p>Mostrar contenido <b>v-text</b> --> <span v-text="contenidoPLAIN"></span></p>
    <p>Mostrar contenido <b>v-html</b> --> <span v-html="contenidoHTML"></span></p>
    <hr>
    <h1>Data binding</h1>
    <p><span>Descripción</span><input type="text" v-model="descripcion">Descripción: <b>v-model --> </b> {{descripcion}}</p>
    <p><span v-bind:class="colores[Math.floor(Math.random() * 2)]">Texto de cambia de color <b>v-bind:class</b></span></p>
    <hr>
    <h1>Computed properties</h1>
    <p><span>Precio</span><input type="number" v-model="precio"> --> IVA (21%) {{ calcularEdad }}</p>
    <hr>
    <h1>Watchers</h1>
    <p>Descripcion<input type="text" v-model="descripcion">{{descripcion}}</p>
    <hr>
    <h1>Eventos</h1>
    <p>Nombre<input type="text" v-model="nombre"><button v-on:click="nombreMatyusculas()">Mayusculas</button></p>
  </div>
</template>

<script>
export default {
  name: 'app',
  data () {
    return {
      mensaje: 'Hola mundo VueJS',
      datos: {
        latitude: 3.44343212,
        longitude: 40.1213433
      },
      mostrar: true,
      dias: [
        'Lunes', 'Martes', 'Miercoles', 'Jueves', 'Viernes', 'Sabado', 'Domingo'
      ],
      contenidoHTML: '<h1>v-html</h1>',
      contenidoPLAIN: 'v-text',
      descripcion: '',
      colores: ['red', 'blue', 'green'],
      precio: 10,
      nombre: ''
    }
  },
  computed: {
    calcularEdad () {
      let p = parseFloat(this.precio * 0.21)
      return p
    }
  },
  watch: {
    descripcion (valorNuevo, valorAnterior) {
      console.log(valorNuevo, valorAnterior)
    }
  },
  methods: {
    suma (a, b) {
      console.log(a + b)
    },
    nombreMatyusculas () {
      this.nombre = this.nombre.toUpperCase()
      this.suma(10, 10)
    }
  }
}
</script>

<style lang="scss">
.red {
  color: red;
}
.green {
  color: green;
}
.blue {
  color: blue;
}
#app {
  font-family: 'Avenir', Helvetica, Arial, sans-serif;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  text-align: center;
  color: #2c3e50;
  margin-top: 60px;
}
h1, h2 {
  font-weight: normal;
}
</style>

Algunos ejemplos de eventos usando v-on:

  • v-on:click@click -> Evento click.
  • v-on:click.stop -> Para la propagación .
  • v-on:keyup.enter -> Liberar la tecla enter.
  • v-on=»{ mouseover: x, click: y, keydown: z}» -> Múltiples eventos.

Bien, con esto finalizamos esta segunda parte del curso de VueJs. 

En breve un ejemplo usando alguna de las cosas que hemos visto.