- Evolución del front end y Vue.js
El desarrollo frontend ha pasado de manipular el DOM a mano con JavaScript vanilla, a usar librerías como jQuery y, finalmente, frameworks que abstraen casi toda la gestión del DOM. Entre los más utilizados están React, Angular y Vue.js.
Vue.js 3 se centra en la Composition API, una forma de organizar la lógica de los componentes a través de la función setup.
- Instancia mínima con Composition API
El siguiente ejemplo muestra cómo crear una aplicación Vue 3, declarar una variable reactiva y mostrarla en la plantilla.
<html lang="es">
<head>
<meta charset="UTF-8">
<title>Primeros pasos con Vue</title>
</head>
<body>
<div id="app">
<h1>Hola, {{ usuario }}</h1>
</div>
<script type="module">
import { createApp, ref } from 'https://unpkg.com/vue@3/dist/vue.esm-browser.js';
createApp({
setup() {
const usuario = ref('Ana');
return { usuario };
}
}).mount('#app');
</script>
</body>
</html>
- Cómo funciona la reactividad
Vue 3 utiliza Proxy para interceptar lecturas y escrituras sobre objetos. Esto permite que cualquier cambio en los datos se refleje automáticamente en la interfaz, sin manipular el DOM directamente.
<script type="module">
const datos = { ciudad: 'Madrid', temperatura: 25 };
const estado = new Proxy(datos, {
get(objeto, propiedad) {
console.log(`Leyendo ${propiedad}`);
return objeto[propiedad];
},
set(objeto, propiedad, valor) {
console.log(`Actualizando ${propiedad} a ${valor}`);
objeto[propiedad] = valor;
return true;
}
});
estado.temperatura = 30;
</script>
Además, Vue construye un DOM virtual que compara con el DOM real para aplicar únicamente los cambios necesarios, mejorando el rendimiento.
- Módulos ES en JavaScript
Vue 3 recomienda usar módulos ECMAScript para dividir el código.
// mathUtils.js
export const sumar = (a, b) => a + b;
export const PI = 3.1416;
// main.js
import { sumar, PI } from './mathUtils.js';
import utilidades from './utilidades.js';
- Variables y funciones reactivas
Dentro de setup se declaran las variables y funciones que Vue debe rastrear. Existen dos herramientas principales:
ref: para valores primitivos y también objetos. En JavaScript se accede mediante.value.reactive: para objetos. No requiere.value.
<div id="app">
<p>{{ mensaje }}</p>
<p>{{ perfil.nombre }} tiene {{ perfil.edad }} años</p>
<button @click="incrementarEdad">Cumplir años</button>
</div>
<script type="module">
import { createApp, ref, reactive } from 'https://unpkg.com/vue@3/dist/vue.esm-browser.js';
createApp({
setup() {
const mensaje = ref('Bienvenido a Vue 3');
const perfil = reactive({ nombre: 'Luis', edad: 28 });
const incrementarEdad = () => {
perfil.edad++;
};
return { mensaje, perfil, incrementarEdad };
}
}).mount('#app');
</script>
- Directivas de plantilla
6.1 Interpolación y v-html
La doble llave {{ }} muestra texto plano. Para renderizar HTML se usa v-html, aunque debe evitarse con contenido no confiable.
<div id="app">
<p>Usuario: {{ nombre }}</p>
<div v-html="contenidoHtml"></div>
</div>
6.2 v-bind: enlace de atributos
v-bind vincula atributos HTML a variables. Su forma abreviada es :.
<div id="app">
<input :type="tipoCampo" :disabled="bloqueado" :value="texto">
<div :class="{ activo: estaActivo, borde: tieneBorde }" ></div>
</div>
6.3 v-if, v-else-if, v-else y v-show
v-if añade o elimina elementos del DOM según una condición. v-show solo cambia la visibilidad mediante CSS.
<div v-if="sesionIniciada">Bienvenido</div>
<div v-else>Inicia sesión para continuar</div>
<div v-show="mostrarAnuncio">Anuncio promocional</div>
6.4 v-on: manejo de eventos
La directiva v-on escucha eventos y su forma abreviada es @.
<div id="app">
<p>Contador: {{ contador }}</p>
<button @click="sumar">Sumar</button>
</div>
<script type="module">
import { createApp, ref } from 'https://unpkg.com/vue@3/dist/vue.esm-browser.js';
createApp({
setup() {
const contador = ref(0);
const sumar = () => contador.value++;
return { contador, sumar };
}
}).mount('#app');
</script>
6.5 v-model: enlace bidireccional
v-model mantiza sincronizada una variable con el valor de un elemento de formulario.
<div id="app">
<input type="text" v-model="nombre">
<p>Hola, {{ nombre }}</p>
<label><input type="radio" v-model="talla" value="S"> S</label>
<label><input type="radio" v-model="talla" value="M"> M</label>
<p>Talla seleccionada: {{ talla }}</p>
<label><input type="checkbox" v-model="intereses" value="deportes"> Deportes</label>
<label><input type="checkbox" v-model="intereses" value="musica"> Música</label>
<p>Intereses: {{ intereses }}</p>
<select v-model="pais">
<option value="">Selecciona un país</option>
<option value="es">España</option>
<option value="mx">México</option>
<option value="ar">Argentina</option>
</select>
<p>País: {{ pais }}</p>
</div>
<script type="module">
import { createApp, ref } from 'https://unpkg.com/vue@3/dist/vue.esm-browser.js';
createApp({
setup() {
const nombre = ref('');
const talla = ref('M');
const intereses = ref([]);
const pais = ref('');
return { nombre, talla, intereses, pais };
}
}).mount('#app');
</script>
6.6 v-for: listas dinámicas
v-for genera elementos a partir de un arreglo. Es recomendable usar :key para ayudar a Vue a identificar cada elemento.
<div id="app">
<ul>
<li v-for="(tarea, indice) in tareas" :key="tarea.id">
{{ indice + 1 }}. {{ tarea.titulo }}
</li>
</ul>
</div>
<script type="module">
import { createApp, ref } from 'https://unpkg.com/vue@3/dist/vue.esm-browser.js';
createApp({
setup() {
const tareas = ref([
{ id: 1, titulo: 'Aprender Vue 3' },
{ id: 2, titulo: 'Practicar Composition API' },
{ id: 3, titulo: 'Construir un proyecto' }
]);
return { tareas };
}
}).mount('#app');
</script>
- Ciclo de vida con onMounted
Los hooks de ciclo de vida permiten ejecutar código en momentos específicos. onMounted se ejecuta tras renderizar el componente y es el lugar habitual para cargar datos del servidor.
<div id="app">
<ul>
<li v-for="elemento in elementos" :key="elemento.id">{{ elemento.nombre }}</li>
</ul>
</div>
<script type="module">
import { createApp, ref, onMounted } from 'https://unpkg.com/vue@3/dist/vue.esm-browser.js';
createApp({
setup() {
const elementos = ref([]);
onMounted(async () => {
const respuesta = await fetch('https://api.example.com/items');
elementos.value = await respuesta.json();
});
return { elementos };
}
}).mount('#app');
</script>