Componentes en Vue.js

Definición de componentes

Hoy vamos a aprender cómo definir y utilizar componentes en Vue.js. Los componentes permiten dividir la interfaz de usuario en piezas reutilizables y gestionables. Esto hace que el desarrollo de aplicaciones sea más organizado y eficiente.

Código de Ejemplo

				
					<!DOCTYPE html>
<html>
<head>
  <title>Definición de Componentes en Vue.js</title>
  <script src="https://unpkg.com/vue@next"></script> <!-- Importamos Vue.js -->
</head>
<body>
  <div id="app">
    <greeting></greeting> <!-- Uso del componente Greeting -->
    <button-counter></button-counter> <!-- Uso del componente ButtonCounter -->
  </div>

  <script>
    // Definición del componente Greeting
    const Greeting = {
      template: `<h1>{{ message }}</h1>`, // Plantilla del componente
      data() {
        return {
          message: '¡Hola, desde el componente Greeting!' // Datos del componente
        };
      }
    };

    // Definición del componente ButtonCounter
    const ButtonCounter = {
      template: `
        <div>
          <button @click="count++">Has clicado {{ count }} veces</button>
        </div>
      `, // Plantilla del componente
      data() {
        return {
          count: 0 // Datos del componente
        };
      }
    };

    const app = Vue.createApp({
      components: {
        'greeting': Greeting, // Registro del componente Greeting
        'button-counter': ButtonCounter // Registro del componente ButtonCounter
      }
    });

    app.mount('#app');
  </script>
</body>
</html>

				
			

Explicación

Definición de Componentes

En Vue.js, un componente se define como un objeto JavaScript que incluye al menos una plantilla y datos. Los componentes encapsulan la lógica, los datos y la presentación de una parte de la interfaz de usuario.

  1. Componente Greeting:

    • Template: La plantilla del componente se define en la propiedad template y contiene el HTML que se va a renderizar.
    • Data: La propiedad data es una función que devuelve un objeto con las propiedades reactivas del componente.
    • Uso: <greeting></greeting> se usa en el HTML para renderizar el componente.
  2. Componente ButtonCounter:

    • Template: Define un botón que incrementa un contador cada vez que se hace clic.
    • Data: La propiedad count se inicializa en 0 y se incrementa cada vez que se hace clic en el botón.
    • Uso: <button-counter></button-counter> se usa en el HTML para renderizar el componente.

Registro de Componentes

Los componentes deben ser registrados en la instancia de Vue para que puedan ser utilizados en la aplicación.

  • Registro Local:
    • En el ejemplo, registramos los componentes Greeting y ButtonCounter localmente dentro de la instancia de Vue usando la propiedad components.

Uso de Componentes

Una vez registrados, los componentes se pueden utilizar en la plantilla de la aplicación mediante sus nombres.

  • <greeting></greeting>: Renderiza el componente Greeting.
  • <button-counter></button-counter>: Renderiza el componente ButtonCounter.

Resumen

  • Definición de Componentes: Los componentes en Vue.js se definen como objetos que incluyen una plantilla y datos.
  • Registro de Componentes: Los componentes deben ser registrados en la instancia de Vue para que puedan ser utilizados.
  • Uso de Componentes: Los componentes se utilizan en la plantilla de la aplicación mediante sus nombres.

Los componentes permiten dividir la interfaz de usuario en partes reutilizables y manejables, lo que hace que el desarrollo de aplicaciones sea más organizado y eficiente.

Comunicación entre componentes (props, eventos)

Los componentes en Vue.js pueden comunicarse entre sí utilizando props y eventos. Este mecanismo permite pasar datos de un componente padre a un componente hijo y viceversa, manteniendo nuestras aplicaciones modulares y organizadas.

Código de Ejemplo

				
					<!DOCTYPE html>
<html>
<head>
  <title>Comunicación entre Componentes en Vue.js</title>
  <script src="https://unpkg.com/vue@next"></script> <!-- Importamos Vue.js -->
</head>
<body>
  <div id="app">
    <!-- Componente padre -->
    <parent-component></parent-component>
  </div>

  <script>
    // Componente hijo
    const ChildComponent = {
      template: `
        <div>
          <h2>{{ title }}</h2>
          <button @click="notifyParent">Notificar al Padre</button>
        </div>
      `,
      props: ['title'], // Recibe la prop 'title' del componente padre
      methods: {
        notifyParent() {
          this.$emit('notify', '¡Hola desde el componente hijo!'); // Emite un evento personalizado 'notify'
        }
      }
    };

    // Componente padre
    const ParentComponent = {
      template: `
        <div>
          <child-component :title="parentTitle" @notify="handleNotification"></child-component>
          <p>Mensaje del hijo: {{ messageFromChild }}</p>
        </div>
      `,
      components: {
        'child-component': ChildComponent // Registro del componente hijo
      },
      data() {
        return {
          parentTitle: 'Título desde el componente padre', // Propiedad a pasar como prop
          messageFromChild: '' // Mensaje recibido desde el componente hijo
        };
      },
      methods: {
        handleNotification(message) {
          this.messageFromChild = message; // Maneja el evento y actualiza el mensaje
        }
      }
    };

    const app = Vue.createApp({
      components: {
        'parent-component': ParentComponent // Registro del componente padre
      }
    });

    app.mount('#app');
  </script>
</body>
</html>

				
			

Explicación

Comunicación del Padre al Hijo (props)

Las props permiten pasar datos desde un componente padre a un componente hijo. En nuestro ejemplo, el componente ParentComponent pasa una prop llamada title al ChildComponent.

  • Definición en el Padre:

    • En el ParentComponent, definimos una propiedad parentTitle que queremos pasar al hijo.
    • Utilizamos la directiva v-bind o el atajo : para pasar la prop: <child-component :title="parentTitle"></child-component>.
  • Recepción en el Hijo:

    • En el ChildComponent, definimos que recibimos una prop llamada title usando la propiedad props.
    • Luego, podemos usar esta prop dentro de la plantilla del componente hijo: <h2>{{ title }}</h2>.

Comunicación del Hijo al Padre (eventos)

Para enviar datos desde un componente hijo a un componente padre, el hijo puede emitir eventos personalizados que el padre escuchará y manejará.

  • Emitir un Evento en el Hijo:

    • En el ChildComponent, definimos un método notifyParent que emite un evento personalizado usando this.$emit('notify', 'message').
    • Este evento se llama notify y lleva un mensaje '¡Hola desde el componente hijo!'.
  • Escuchar y Manejar el Evento en el Padre:

    • En el ParentComponent, usamos @notify="handleNotification" para escuchar el evento notify emitido por el hijo.
    • Definimos un método handleNotification en el padre que recibe el mensaje del hijo y lo maneja. En este caso, actualiza la propiedad messageFromChild.

Resumen

  • Props: Se utilizan para pasar datos desde un componente padre a un componente hijo. Se definen en el padre y se reciben en el hijo usando la propiedad props.
  • Eventos: Se utilizan para enviar datos desde un componente hijo a un componente padre. El hijo emite un evento personalizado usando this.$emit y el padre escucha y maneja el evento usando @evento="método".

Esta comunicación entre componentes hace que la estructura de tus aplicaciones Vue.js sea más modular y organizada, permitiendo una interacción eficiente entre diferentes partes de la aplicación.

Ciclo de vida de los componentes

Cada componente en Vue.js pasa por una serie de etapas desde su creación hasta su destrucción. Vue proporciona varios hooks del ciclo de vida que nos permiten ejecutar código en diferentes momentos del ciclo de vida de un componente.

Código de Ejemplo

				
					<!DOCTYPE html>
<html>
<head>
  <title>Ciclo de Vida de los Componentes en Vue.js</title>
  <script src="https://unpkg.com/vue@next"></script> <!-- Importamos Vue.js -->
</head>
<body>
  <div id="app">
    <life-cycle-demo></life-cycle-demo> <!-- Uso del componente LifeCycleDemo -->
  </div>

  <script>
    const LifeCycleDemo = {
      template: `
        <div>
          <h1>Ciclo de Vida del Componente</h1>
          <p>Mensaje: {{ message }}</p>
        </div>
      `,
      data() {
        return {
          message: '¡Hola, Vue.js!'
        };
      },
      beforeCreate() {
        console.log('beforeCreate: El componente está siendo creado.');
      },
      created() {
        console.log('created: El componente ha sido creado.');
      },
      beforeMount() {
        console.log('beforeMount: El componente está a punto de ser montado en el DOM.');
      },
      mounted() {
        console.log('mounted: El componente ha sido montado en el DOM.');
      },
      beforeUpdate() {
        console.log('beforeUpdate: El componente está a punto de ser actualizado.');
      },
      updated() {
        console.log('updated: El componente ha sido actualizado.');
      },
      beforeUnmount() {
        console.log('beforeUnmount: El componente está a punto de ser desmontado.');
      },
      unmounted() {
        console.log('unmounted: El componente ha sido desmontado.');
      }
    };

    const app = Vue.createApp({
      components: {
        'life-cycle-demo': LifeCycleDemo // Registro del componente LifeCycleDemo
      }
    });

    app.mount('#app');
  </script>
</body>
</html>

				
			

Explicación

Hooks del Ciclo de Vida

Los hooks del ciclo de vida son métodos que Vue llama en ciertos momentos del ciclo de vida de un componente. Aquí están los hooks más importantes y lo que hacen:

  1. beforeCreate: Se llama justo antes de que se cree el componente. En este punto, los datos del componente aún no están disponibles.

    • beforeCreate() { console.log('beforeCreate: El componente está siendo creado.'); }
  2. created: Se llama inmediatamente después de que el componente ha sido creado. En este punto, los datos del componente están disponibles, pero aún no se ha montado en el DOM.

    • created() { console.log('created: El componente ha sido creado.'); }
  3. beforeMount: Se llama justo antes de que el componente se monte en el DOM. El template del componente ha sido compilado y está a punto de ser insertado en el DOM.

    • beforeMount() { console.log('beforeMount: El componente está a punto de ser montado en el DOM.'); }
  4. mounted: Se llama cuando el componente ha sido montado en el DOM. Este es un buen lugar para operaciones que dependen del DOM, como trabajar con librerías que manipulan el DOM.

    • mounted() { console.log('mounted: El componente ha sido montado en el DOM.'); }
  5. beforeUpdate: Se llama cuando los datos del componente cambian, pero antes de que el DOM se actualice. Este hook permite acceder al estado anterior del DOM antes de la actualización.

    • beforeUpdate() { console.log('beforeUpdate: El componente está a punto de ser actualizado.'); }
  6. updated: Se llama después de que los datos del componente han cambiado y el DOM ha sido actualizado. Es un buen lugar para realizar operaciones que dependen del nuevo estado del DOM.

    • updated() { console.log('updated: El componente ha sido actualizado.'); }
  7. beforeUnmount: Se llama justo antes de que el componente se desmonte y destruya. Es un buen lugar para limpiar recursos, como timers o suscripciones.

    • beforeUnmount() { console.log('beforeUnmount: El componente está a punto de ser desmontado.'); }
  8. unmounted: Se llama después de que el componente ha sido desmontado y destruido. En este punto, todos los eventos y bindings asociados han sido eliminados.

    • unmounted() { console.log('unmounted: El componente ha sido desmontado.'); }

Resumen

  • beforeCreate: El componente está siendo creado, los datos aún no están disponibles.
  • created: El componente ha sido creado, los datos están disponibles pero el DOM aún no.
  • beforeMount: El componente está a punto de ser montado en el DOM.
  • mounted: El componente ha sido montado en el DOM, el DOM está disponible.
  • beforeUpdate: Los datos han cambiado, pero el DOM aún no se ha actualizado.
  • updated: El DOM ha sido actualizado con los nuevos datos.
  • beforeUnmount: El componente está a punto de ser desmontado del DOM.
  • unmounted: El componente ha sido desmontado y destruido.

Estilización de Componentes

Vue.js nos ofrece varias maneras de aplicar estilos a nuestros componentes, permitiendo tanto estilos globales como locales (scoped). Vamos a ver cómo funciona todo esto con un ejemplo práctico.

Código de Ejemplo

				
					<!DOCTYPE html>
<html>
<head>
  <title>Estilización de Componentes en Vue.js</title>
  <script src="https://unpkg.com/vue@next"></script> <!-- Importamos Vue.js -->
  <style>
    /* Estilos globales */
    body {
      font-family: Arial, sans-serif;
      background-color: #f0f0f0;
      margin: 0;
      padding: 20px;
    }
  </style>
</head>
<body>
  <div id="app">
    <styled-component></styled-component> <!-- Uso del componente StyledComponent -->
  </div>

  <script>
    const StyledComponent = {
      template: `
        <div class="styled-component">
          <h1 class="title">Estilización de Componentes</h1>
          <p class="content">Este es un ejemplo de cómo estilizar componentes en Vue.js.</p>
        </div>
      `,
      data() {
        return {};
      },
      styles: `
        <style scoped>
          .styled-component {
            background-color: #fff;
            padding: 20px;
            border-radius: 8px;
            box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
          }
          .title {
            color: #2c3e50;
          }
          .content {
            color: #34495e;
          }
        </style>
      `
    };

    const app = Vue.createApp({
      components: {
        'styled-component': StyledComponent // Registro del componente StyledComponent
      }
    });

    app.mount('#app');
  </script>
</body>
</html>

				
			

Explicación

Estilos Globales

Los estilos globales se aplican a toda la aplicación y se definen típicamente en el archivo HTML principal o en un archivo CSS separado. En nuestro ejemplo, los estilos globales están definidos dentro del bloque <style> en el <head> del documento HTML.

				
					<style>
  /* Estilos globales */
  body {
    font-family: Arial, sans-serif;
    background-color: #f0f0f0;
    margin: 0;
    padding: 20px;
  }
</style>

				
			

Estos estilos se aplicarán a todo el documento, afectando a todos los componentes.

Estilos Scoped

Los estilos scoped se aplican solo al componente en el que están definidos. Esto asegura que los estilos no afecten a otros componentes, manteniendo el encapsulamiento y la modularidad. En Vue.js, los estilos scoped se definen utilizando la directiva scoped dentro del bloque <style> en el archivo del componente.

				
					<style scoped>
  .styled-component {
    background-color: #fff;
    padding: 20px;
    border-radius: 8px;
    box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
  }
  .title {
    color: #2c3e50;
  }
  .content {
    color: #34495e;
  }
</style>

				
			

Plantilla del Componente

La plantilla del componente StyledComponent incluye clases CSS que se definen en el bloque de estilos scoped. Estas clases aseguran que los estilos se apliquen solo a los elementos de este componente.

				
					<template>
  <div class="styled-component">
    <h1 class="title">Estilización de Componentes</h1>
    <p class="content">Este es un ejemplo de cómo estilizar componentes en Vue.js.</p>
  </div>
</template>

				
			

Resumen

  • Estilos Globales: Se aplican a toda la aplicación y se definen en el archivo HTML principal o en un archivo CSS separado. Afectan a todos los componentes.
  • Estilos Scoped: Se aplican solo al componente en el que están definidos. Se definen utilizando la directiva scoped dentro del bloque <style>, manteniendo el encapsulamiento y la modularidad.
  • Uso de Clases CSS: Los estilos scoped se aplican a través de clases CSS definidas en el bloque <style> y se utilizan en la plantilla del componente.

Uso de preprocesadores CSS (Sass, Less)

Los preprocesadores CSS nos permiten escribir CSS de manera más eficiente y con características avanzadas como variables, anidamiento y mixins.

Código de Ejemplo

Vamos a usar Sass en este ejemplo. Asegúrate de tener Node.js y Vue CLI instalados.

				
					# Primero, crea un proyecto Vue si no lo tienes ya
vue create my-vue-app
cd my-vue-app

# Instala Sass
npm install -D sass

				
			

Archivo App.vue con Sass

				
					<template>
  <div class="styled-component">
    <h1 class="title">Uso de Preprocesadores CSS (Sass) en Vue.js</h1>
    <p class="content">Este es un ejemplo de cómo usar Sass en un componente Vue.js.</p>
  </div>
</template>

<script>
export default {
  name: 'StyledComponent'
};
</script>

<style lang="scss" scoped>
$primary-color: #2c3e50;
$secondary-color: #34495e;
$background-color: #fff;
$padding: 20px;

.styled-component {
  background-color: $background-color;
  padding: $padding;
  border-radius: 8px;
  box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);

  .title {
    color: $primary-color;
  }

  .content {
    color: $secondary-color;
  }
}
</style>

				
			

Archivo main.js

				
					import { createApp } from 'vue';
import App from './App.vue';

createApp(App).mount('#app');

				
			

Explicación

Instalación de Sass

Para utilizar Sass en tu proyecto Vue.js, primero necesitas instalar la dependencia de Sass. Puedes hacerlo ejecutando el comando npm install -D sass en tu terminal dentro de tu proyecto Vue.js.

Uso de Sass en el Componente Vue

  1. Template: Define la estructura HTML de tu componente.
  2. Script: Exporta el componente.
  3. Style: Define los estilos utilizando Sass.

Variables Sass

En el bloque de estilos, utilizamos variables de Sass para definir colores y otros valores reutilizables:

				
					$primary-color: #2c3e50;
$secondary-color: #34495e;
$background-color: #fff;
$padding: 20px;

				
			

Anidamiento

Sass permite anidar selectores CSS dentro de otros selectores, lo que hace que el código CSS sea más limpio y legible:

				
					.styled-component {
  background-color: $background-color;
  padding: $padding;
  border-radius: 8px;
  box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);

  .title {
    color: $primary-color;
  }

  .content {
    color: $secondary-color;
  }
}

				
			

Directiva scoped y lang

  • scoped: Mantiene los estilos locales al componente, asegurando que no afecten a otros componentes.
  • lang="scss": Indica que estamos utilizando Sass en lugar de CSS.

Resumen

  • Instalación de Sass: Instala Sass en tu proyecto Vue.js usando npm install -D sass.
  • Uso de Variables: Define variables Sass para colores y otros valores reutilizables.
  • Anidamiento: Anida selectores CSS dentro de otros selectores para un código más limpio y legible.
  • Directiva scoped y lang: Usa scoped para mantener los estilos locales y lang="scss" para indicar que se está utilizando Sass.