Si estás al tanto de los frameworks JavaScript más usados hoy en día, seguramente habrás escuchado hablar de Vue.js. Si no has escuchado acerca de él, a continuación te lo describiré rápidamente.
En este tutorial se utiliza ECMA Script 2015 para el código JavaScript. Si no estás familiarizado con el nuevo estándar, te recomiendo que le eches una rápida ojeada al siguiente artículo: Aprende ECMAScript 2015 si no lo has hecho ya.
¿Qué es Vue?
Vue es un framework progresivo para crear interfaces de usuario y básicamente es una capa centrada en la vista. Tiene una curva de aprendizaje bastante baja, es fácil de integrar con otros frameworks o librerías y es muy sencillo de implementar en cualquier proyecto.
Tutorial de iniciación
En este pequeño tutorial, vamos a crear una sencilla aplicación de lista de tareas, con la posibilidad de crear tareas, terminarlas o borrarlas. Para ello, vamos a utilizar algunas de las directivas más importantes de Vue y aprenderemos cómo añadir interactividad por medio de eventos.
Para la realización de este tutorial utilizaré las clases CSS de Bootstrap para agilizar el proceso y centrarnos en lo más importante que es trabajar con Vue.
Estructura HTML
Comenzaremos creando un fichero HTML en el que añadiremos los estilos de Bootstrap y el framework Vue:
<!DOCTYPE html>
<html>
<head>
<title>Vue.js tutorial</title>
<meta charset="utf-8">
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.1.0/css/bootstrap.min.css" integrity="sha384-9gVQ4dYFwwWSjIDZnLEWnxCjeSWFphJiwGPXr1jddIhOegiu1FwO5qRGvFXOdJZ4" crossorigin="anonymous">
</head>
<body>
<script src="https://cdn.jsdelivr.net/npm/vue@2.6.14"></script>
</body>
</html>
Más adelante, en el body, crearemos una tabla Bootstrap con la siguiente estructura:
<body>
<table id="lista" class="table table-bordered">
<thead class="thead-light">
<tr>
<th scope="col" width="5%">#</th>
<th scope="col" width="85%">
<label for="nombre-tarea">Nombre de la tarea</label>
<input type="text" class="form-control" id="nombre-tarea">
</th>
<th scope="col" width="10%">
<button type="button" class="btn btn-primary btn-block">Añadir</button>
</th>
</tr>
</thead>
<tbody>
<tr>
<th scope="row"></th>
<td></td>
<td>
<button type="button" class="btn btn-sm btn-warning btn-block">Eliminar</button>
<button type="button" class="btn btn-sm btn-secondary btn-block">Completar</button>
</td>
</tr>
</tbody>
</table>
<script src="https://cdn.jsdelivr.net/npm/vue@2.6.14"></script>
</body>
Este será el resultado del anterior código:
Instancia Vue
Ahora crearemos la instancia de Vue que utilizará nuestra aplicación. La situaré en un fichero JavaScript separado (lista-vue.js) que incluiré en el HTML:
const app = new Vue({
el: "#lista",
data: {},
methods: {}
});
El parámetro el hará referencia al elemento raíz de la instancia, en este caso se trata de la tabla que acabamos de crear con id lista. El parámetro data es un objeto que contendrá todos los datos que queramos utilizar en nuestra instancia. Y por último, el parámetro methods, contendrá todos los métodos que ejecutaremos en la instancia.
Comenzaremos por añadir a los datos un array de objetos consistente en la lista de tareas, este array lo utilizaremos más tarde para crear las filas de la tabla:
const app = new Vue({
el: "#lista",
data: {
lista: [
{nombre: "Ir a la escuela a recoger las notas", completado: true},
{nombre: "Llevar al perro al veterinario", completado: false},
{nombre: "Llamar a Marta a su casa", completado: false}
]
},
methods: {}
});
Trabajo con directivas
Ahora veremos cómo podemos hacer uso de este array para representar una fila de la tabla por cada elemento que en él se encuentre. Para hacerlo, nos valdremos de la directiva v-for. Esta directiva se utiliza para crear un ciclo y representar un elemento múltiples veces dependiendo de los datos que se le pasen:
<tbody>
<tr v-for="(item, index) in lista">
<th scope="row">{{index + 1}}</th>
<td>{{item.nombre}}</td>
<td>
...
...
</td>
</tr>
</tbody>
Como vemos, estamos haciendo un ciclo sobre el array lista. En cada iteración situamos el índice del array incrementado en uno dentro del th y la propiedad nombre de cada objeto dentro del elemento td de cada fila. El resultado será el siguiente:
El próximo paso será ocultar o mostrar los botones Eliminar y Completar dependiendo del valor de la propiedad completado de cada objeto del array. Vamos a mostrar el botón Completar solamente cuando esta propiedad tenga valor false y el botón Eliminar solamente cuando este sea true. Para lograr esto, nos valdremos de las directivas v-if y v-else. Estas directivas nos permiten representar o no un elemento en el DOM dependiendo de una condición específica:
<tbody>
<tr v-for="(fila, index) in lista">
...
...
</td>
<td>
<button v-if="fila.completado" type="button" class="btn btn-sm btn-warning btn-block">Eliminar</button>
<button v-else type="button" class="btn btn-sm btn-secondary btn-block">Completar</button>
</td>
</tr>
</tbody>
El resultado será el siguiente:
A continuación, para comunicar de manera más clara cuándo una tarea está completada, vamos a tachar el nombre de la tarea en estos casos. Para hacer esto nos valdremos de la directiva v-show. Esta directiva conmutará la propiedad CSS display: none dependiendo de una condición. Es decir, a diferencia de con v-if y v-else, el elemento siempre se representará en el DOM, solo que este estará visible o no dependiendo de una condición:
<tr v-for="(fila, index) in lista">
...
...
<td>
<del v-show="fila.completado">
{{fila.nombre}}
</del>
<span v-show="!fila.completado">
{{fila.nombre}}
</span>
</td>
<td>
...
...
</td>
</tr>
Cuando la propiedad completado de cada fila tenga valor true, mostraremos un elemento del con el nombre de la tarea dentro (si es false este elemento permanecerá oculto). Y por otro lado, cuando la propiedad sea false mostraremos un span con el nombre dentro (si es true este elemento permanecerá oculto). El resultado será el siguiente:
Uniones bidireccionales (two-way binding)
Ahora crearemos una propiedad nombre dentro del objeto data que por defecto tendrá como valor una cadena vacía:
const app = new Vue({
el: "#lista",
data: {
nombre: "",
lista: [
{nombre: "Ir a la escuela a recoger las notas", completado: true},
{nombre: "Llevar al perro al veterinario", completado: false},
{nombre: "Llamar a Marta a su casa", completado: false}
]
},
methods: {}
});
Y a continuación, uniremos el valor del input del nombre a esta propiedad que acabamos de crear mediante la directiva v-model. Esta directiva creará una unión bidireccional (two-way binding) entre el valor del input y dicha propiedad. Una vez que el input cambie su valor la propiedad se verá actualizada y viceversa:
<thead class="thead-light">
<tr>
<th scope="col" width="5%">#</th>
<th scope="col" width="85%">
<label for="nombre-tarea">Nombre de la tarea</label>
<input type="text" class="form-control" id="nombre-tarea" v-model="nombre">
</th>
<th scope="col" width="10%">
...
...
</th>
</tr>
</thead>
Añadiendo interactividad
Ya podemos añadir interactividad a nuestra lista de tareas. Para ello nos será de ayuda la directiva v-on, la cual nos servirá para escuchar los eventos del DOM. En este caso vamos a utilizar los métodos abreviados de esta directiva.
Empezaremos por añadir un evento click al botón Añadir, el cual llamará al método add dentro del objeto methods:
<thead class="thead-light">
<tr>
...
...
<th scope="col" width="10%">
<button type="button" @click="add" class="btn btn-primary btn-block">Añadir</button>
</th>
</tr>
</thead>
Y en la instancia:
methods: {
add () {
this.lista.push({nombre: this.nombre, completado: false});
this.nombre = "";
}
}
Al presionar el botón Añadir añadiremos un nuevo objeto al array. Nótese cómo se utiliza para el nombre la propiedad nombre que usa el input como modelo. Una vez se haya añadido el objeto al array, volvemos a asignar a la propiedad nombre una cadena vacía como valor.
Prueba el resultado y verás que ya puedes escribir el nombre de una tarea y añadirla a la lista presionando el botón Añadir.
Ahora añadiremos un evento click al botón Completar. Este evento solo asignará el valor true a la propiedad completado:
<tbody>
<tr v-for="(fila, index) in lista">
...
...
<td>
<button v-if="fila.completado" type="button" class="btn btn-sm btn-warning btn-block">Eliminar</button>
<button v-else type="button" class="btn btn-sm btn-secondary btn-block" @click="fila.completado = true">Completar</button>
</td>
</tr>
</tbody>
Prueba el resultado y verás que ya puedes finalizar una tarea presionando el botón Completar. Una vez que lo hagas, este botón desaparecerá mostrando en su lugar el botón Eliminar y el nombre de la tarea quedará tachado.
Y por último crearemos un evento click en el botón Eliminar que a su vez ejecutará el método del que crearemos dentro de methods:
<tbody>
<tr v-for="(fila, index) in lista">
...
...
<td>
<button v-if="fila.completado" type="button" class="btn btn-sm btn-warning btn-block" @click="del(index)">Eliminar</button>
<button v-else type="button" class="btn btn-sm btn-secondary btn-block" @click="fila.completado = true">Completar</button>
</td>
</tr>
</tbody>
Y en la instancia:
methods: {
add () {
...
},
del (index) {
this.lista.splice(index, 1);
}
}
El método del recibe el índice de la fila en la que se ha clicado el botón y realiza un splice en el array, eliminando el objeto correspondiente a ese índice.
Prueba el resultado final y verás que ya puedes añadir, finalizar y borrar tareas.
Demostración del resultado final
Descarga de ficheros
Y con esto ya tendremos la aplicación de lista de tareas completada. Como puedes ver, empezar a trabajar con Vue no es difícil, es bastante intuitivo y muy fácil de adoptar en poco tiempo. Si quieres profundizar más, puedes consultar su documentación que está bastante completa.
Espero que este pequeño tutorial te haya servido de ayuda para iniciarte con Vue.js.
Descargar los ficheros del tutorial de iniciación a Vue.
Puedes situar fragmentos de código dentro de etiquetas <pre></pre> y código HTML o XML entre etiquetas <xmp></xmp>.