Vue.js


¿Qué es Vue.js?

Vue.js es un framework progresivo de JavaScript para construir interfaces de usuario. Creado por Evan You, Vue se caracteriza por ser fácil de aprender, flexible y escalable, permitiendo adoptarlo gradualmente en proyectos existentes o usarlo para aplicaciones completas.

¿Para qué sirve Vue.js?

Vue.js es ideal para:

  • Interfaces de usuario interactivas y dinámicas.
  • Single Page Applications (SPAs) modernas.
  • Aplicaciones web progresivas (PWAs).
  • Dashboards y paneles de administración.
  • E-commerce y aplicaciones empresariales.
  • Migración gradual desde jQuery o JavaScript vanilla.

¿Cómo funciona?

Vue utiliza un sistema reactivo que actualiza automáticamente la interfaz cuando cambian los datos. Imagina Vue como un asistente inteligente que observa tus datos y actualiza la pantalla instantáneamente cuando algo cambia, sin que tengas que decirle específicamente qué hacer.

Ejemplo: Componente básico en Vue

Vue combina HTML, CSS y JavaScript en componentes de una sola archivo (SFC):

<!-- TodoApp.vue -->
<template>
  <div class="todo-app">
    <h1>{{ title }}</h1>
    
    <form @submit.prevent="addTodo">
      <input 
        v-model="newTodo" 
        placeholder="¿Qué necesitas hacer?"
        required
      />
      <button type="submit">Agregar</button>
    </form>
    
    <ul class="todo-list">
      <li 
        v-for="todo in filteredTodos" 
        :key="todo.id"
        :class="{ completed: todo.completed }"
      >
        <input 
          type="checkbox" 
          v-model="todo.completed"
        />
        <span>{{ todo.text }}</span>
        <button @click="removeTodo(todo.id)">❌</button>
      </li>
    </ul>
    
    <div class="filters">
      <button 
        v-for="filter in filters" 
        :key="filter"
        @click="currentFilter = filter"
        :class="{ active: currentFilter === filter }"
      >
        {{ filter }}
      </button>
    </div>
    
    <p>{{ remainingTodos }} tareas pendientes</p>
  </div>
</template>

<script>
export default {
  name: 'TodoApp',
  data() {
    return {
      title: 'Mi Lista de Tareas',
      newTodo: '',
      currentFilter: 'Todas',
      filters: ['Todas', 'Pendientes', 'Completadas'],
      todos: [
        { id: 1, text: 'Aprender Vue.js', completed: false },
        { id: 2, text: 'Construir una app', completed: true }
      ]
    };
  },
  computed: {
    filteredTodos() {
      switch (this.currentFilter) {
        case 'Pendientes':
          return this.todos.filter(todo => !todo.completed);
        case 'Completadas':
          return this.todos.filter(todo => todo.completed);
        default:
          return this.todos;
      }
    },
    remainingTodos() {
      return this.todos.filter(todo => !todo.completed).length;
    }
  },
  methods: {
    addTodo() {
      if (this.newTodo.trim()) {
        this.todos.push({
          id: Date.now(),
          text: this.newTodo.trim(),
          completed: false
        });
        this.newTodo = '';
      }
    },
    removeTodo(id) {
      this.todos = this.todos.filter(todo => todo.id !== id);
    }
  }
};
</script>

<style scoped>
.todo-app {
  max-width: 500px;
  margin: 0 auto;
  padding: 20px;
}

.todo-list {
  list-style: none;
  padding: 0;
}

.todo-list li {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 10px;
  border-bottom: 1px solid #eee;
}

.completed span {
  text-decoration: line-through;
  opacity: 0.6;
}

.filters button {
  margin: 5px;
  padding: 5px 10px;
  border: 1px solid #ddd;
  background: white;
  cursor: pointer;
}

.filters button.active {
  background: #42b883;
  color: white;
}
</style>

Composition API (Vue 3)

Vue 3 introdujo la Composition API para mejor organización del código:

<template>
  <div>
    <h2>Contador: {{ count }}</h2>
    <button @click="increment">+1</button>
    <button @click="decrement">-1</button>
    <button @click="reset">Reset</button>
    
    <h3>Usuarios</h3>
    <div v-if="loading">Cargando...</div>
    <ul v-else>
      <li v-for="user in users" :key="user.id">
        {{ user.name }} - {{ user.email }}
      </li>
    </ul>
  </div>
</template>

<script setup>
import { ref, computed, onMounted } from 'vue';

// Estado reactivo
const count = ref(0);
const users = ref([]);
const loading = ref(true);

// Computed properties
const isEven = computed(() => count.value % 2 === 0);

// Métodos
const increment = () => count.value++;
const decrement = () => count.value--;
const reset = () => count.value = 0;

// Ciclo de vida
onMounted(async () => {
  try {
    const response = await fetch('https://jsonplaceholder.typicode.com/users');
    users.value = await response.json();
  } catch (error) {
    console.error('Error cargando usuarios:', error);
  } finally {
    loading.value = false;
  }
});
</script>

Directivas de Vue

Vue incluye directivas poderosas para manipular el DOM:

<template>
  <div>
    <!-- Renderizado condicional -->
    <p v-if="isLoggedIn">¡Bienvenido, {{ username }}!</p>
    <p v-else>Por favor, inicia sesión</p>
    
    <!-- Mostrar/ocultar (mantiene en DOM) -->
    <div v-show="showDetails">
      Detalles del usuario...
    </div>
    
    <!-- Loops -->
    <ul>
      <li v-for="(item, index) in items" :key="item.id">
        {{ index + 1 }}. {{ item.name }}
      </li>
    </ul>
    
    <!-- Binding de atributos -->
    <img :src="imageUrl" :alt="imageAlt" />
    <button :disabled="isLoading">{{ buttonText }}</button>
    
    <!-- Clases dinámicas -->
    <div 
      :class="{ 
        active: isActive, 
        disabled: isDisabled,
        'has-error': hasError 
      }"
    >
      Estado dinámico
    </div>
    
    <!-- Estilos dinámicos -->
    <div :style="{ 
      color: textColor, 
      fontSize: fontSize + 'px',
      backgroundColor: bgColor 
    }">
      Estilos dinámicos
    </div>
    
    <!-- Event listeners -->
    <button @click="handleClick">Clic simple</button>
    <button @click.prevent="handleSubmit">Prevenir default</button>
    <input @keyup.enter="handleEnter" />
    
    <!-- Two-way binding -->
    <input v-model="message" placeholder="Escribe algo...">
    <p>Mensaje: {{ message }}</p>
  </div>
</template>

Comunicación entre componentes

Padre a Hijo (Props):

<!-- ParentComponent.vue -->
<template>
  <ChildComponent 
    :title="pageTitle"
    :user="currentUser"
    :is-admin="userIsAdmin"
  />
</template>

<!-- ChildComponent.vue -->
<script setup>
const props = defineProps({
  title: String,
  user: Object,
  isAdmin: {
    type: Boolean,
    default: false
  }
});
</script>

Hijo a Padre (Events):

<!-- ChildComponent.vue -->
<template>
  <button @click="notifyParent">Enviar al padre</button>
</template>

<script setup>
const emit = defineEmits(['user-action', 'data-updated']);

const notifyParent = () => {
  emit('user-action', {
    action: 'button-click',
    timestamp: Date.now()
  });
};
</script>

<!-- ParentComponent.vue -->
<template>
  <ChildComponent @user-action="handleUserAction" />
</template>

Estado global con Pinia

Para aplicaciones más grandes, Vue usa Pinia para gestión de estado:

// stores/user.js
import { defineStore } from 'pinia';

export const useUserStore = defineStore('user', {
  state: () => ({
    currentUser: null,
    isAuthenticated: false,
    preferences: {
      theme: 'light',
      language: 'es'
    }
  }),
  
  getters: {
    fullName: (state) => {
      return state.currentUser ? 
        `${state.currentUser.firstName} ${state.currentUser.lastName}` : 
        'Invitado';
    },
    isAdmin: (state) => {
      return state.currentUser?.role === 'admin';
    }
  },
  
  actions: {
    async login(credentials) {
      try {
        const response = await api.login(credentials);
        this.currentUser = response.user;
        this.isAuthenticated = true;
      } catch (error) {
        throw new Error('Error al iniciar sesión');
      }
    },
    
    logout() {
      this.currentUser = null;
      this.isAuthenticated = false;
    },
    
    updatePreferences(newPreferences) {
      this.preferences = { ...this.preferences, ...newPreferences };
    }
  }
});
<!-- En un componente -->
<template>
  <div>
    <h1>Hola, {{ userStore.fullName }}</h1>
    <button v-if="!userStore.isAuthenticated" @click="showLogin">
      Iniciar Sesión
    </button>
    <button v-else @click="userStore.logout()">
      Cerrar Sesión
    </button>
  </div>
</template>

<script setup>
import { useUserStore } from '@/stores/user';

const userStore = useUserStore();
</script>

Características principales

  • Reactive System: Actualización automática de la UI cuando cambian los datos.
  • Component-Based: Arquitectura basada en componentes reutilizables.
  • Single File Components: HTML, CSS y JS en un solo archivo.
  • Virtual DOM: Renderizado eficiente con reconciliación mínima.
  • Progressive: Se puede adoptar gradualmente en proyectos existentes.
  • Flexible: Múltiples formas de escribir componentes (Options API, Composition API).

Ecosistema Vue

// Principales librerías del ecosistema
const vueEcosystem = {
  // Routing
  'Vue Router': 'Enrutamiento para SPAs',
  
  // Estado global
  'Pinia': 'Gestión de estado (reemplaza Vuex)',
  
  // Build tools
  'Vite': 'Build tool ultra-rápido',
  'Vue CLI': 'Herramienta de línea de comandos',
  
  // UI Libraries
  'Vuetify': 'Material Design components',
  'Quasar': 'Framework completo con muchos componentes',
  'Element Plus': 'Componentes para aplicaciones empresariales',
  
  // Testing
  'Vue Test Utils': 'Utilidades para testing de componentes',
  
  // Meta-frameworks
  'Nuxt.js': 'Framework full-stack para Vue'
};

¿Cuándo usar Vue.js?

  • Proyectos nuevos que necesitan desarrollo rápido.
  • Migración gradual desde jQuery o JavaScript vanilla.
  • Equipos mixtos con diferentes niveles de experiencia.
  • Aplicaciones empresariales que requieren mantenibilidad.
  • Prototipado rápido y MVPs.
  • Cuando necesitas curva de aprendizaje suave.

Comparación con otros frameworks

CaracterísticaVue.jsReactAngular
Curva de aprendizajeSuaveMediaPronunciada
Tamaño de bundlePequeñoPequeñoGrande
PerformanceExcelenteExcelenteMuy buena
EcosistemaCompletoExtensoCompleto
Adopción empresarialAltaMuy altaMuy alta
FlexibilidadAltaAltaMedia
TypeScriptSoporte nativoExcelenteNativo

Ventajas de Vue.js

✅ Fácil de aprender: Sintaxis intuitiva y documentación excelente. ✅ Flexible: Múltiples formas de organizar y escribir código. ✅ Performance: Virtual DOM optimizado y reactivity eficiente. ✅ Ecosistema maduro: Librerías oficiales y comunidad activa. ✅ Progressive: Se puede integrar gradualmente. ✅ Single File Components: Organización clara y mantenible.

Configuración básica

// main.js
import { createApp } from 'vue';
import App from './App.vue';
import router from './router';
import { createPinia } from 'pinia';

const app = createApp(App);

app.use(router);
app.use(createPinia());

app.mount('#app');

Conclusión

Vue.js es el framework perfecto para desarrolladores que buscan productividad sin sacrificar flexibilidad. Su filosofía progresiva y su curva de aprendizaje suave lo hacen ideal tanto para equipos experimentados como para quienes están empezando con frameworks modernos.

Con su sistema reactivo intuitivo, componentes bien organizados y ecosistema maduro, Vue.js te permite construir desde interfaces simples hasta aplicaciones empresariales complejas, manteniendo siempre el código limpio y mantenible.


Usamos cookies para mejorar tu experiencia. ¿Aceptas las cookies de análisis?