02. Estructura del Componente
Estructura de un Componente Vue 3
Section titled “Estructura de un Componente Vue 3”Un componente Vue 3 está compuesto por tres secciones principales: <template>, <script> y <style>. Con Vue 3 y la Composition API, la estructura interna del bloque <script> cambia significativamente, especialmente con la introducción de <script setup>.
Estructura básica
Section titled “Estructura básica”<template><!-- Estructura HTML del componente --><div class="greeting"> <h1>{{ message }}</h1> <button @click="increment">Contador: {{ count }}</button></div></template>
<script>// Lógica del componente</script>
<style>/* Estilos del componente */.greeting { color: #2c3e50;}</style>Ejemplo completo: Contador sin estilos
Section titled “Ejemplo completo: Contador sin estilos”<template><div> <h2>Contador Simple</h2> <p>Valor actual: {{ count }}</p> <button @click="increment">Incrementar</button> <button @click="decrement">Decrementar</button> <button @click="reset">Reiniciar</button></div></template>
<script setup>import { ref } from 'vue'
// Estado reactivo del contadorconst count = ref(0)
// Métodos para manipular el contadorfunction increment() {count.value++}
function decrement() {count.value--}
function reset() {count.value = 0}</script>Template
Section titled “Template”El bloque <template> contiene la estructura HTML del componente. Vue utiliza una sintaxis de plantilla basada en HTML con algunas características especiales:
Interpolación de texto
Section titled “Interpolación de texto”<template> <p>{{ message }}</p> <p>{{ formatDate(date) }}</p></template>Directivas
Section titled “Directivas”Las directivas son atributos especiales con el prefijo v-:
<template> <div v-if="isVisible">Contenido condicional</div> <ul> <li v-for="item in items" :key="item.id">{{ item.name }}</li> </ul> <button v-on:click="handleClick">Click me</button> <input v-model="username" placeholder="Username" /></template>Binding de atributos
Section titled “Binding de atributos”<template> <img :src="imageUrl" :alt="imageDescription"> <div :class="{ active: isActive }" :style="{ color: textColor }"></div></template><template> <slot name="header"></slot> <slot></slot> <!-- slot por defecto --> <slot name="footer"></slot></template>Script Setup
Section titled “Script Setup”Vue 3 introduce <script setup>, una azucar sintáctica para usar Composition API con menos código repetitivo. Todo lo declarado dentro de <script setup> está disponible automáticamente en el template.
<script setup>import { ref, computed, onMounted } from 'vue'
// Variables reactivasconst count = ref(0)const message = ref('Hola Vue 3')
// Propiedades computadasconst doubleCount = computed(() => count.value * 2)
// Métodosfunction increment() { count.value++}
// Hooks de ciclo de vidaonMounted(() => { console.log('Componente montado')})</script><script>import { ref, computed, onMounted } from 'vue'
export default { setup() { // Variables reactivas const count = ref(0) const message = ref('Hola Vue 3')
// Propiedades computadas const doubleCount = computed(() => count.value * 2)
// Métodos function increment() { count.value++ }
// Hooks de ciclo de vida onMounted(() => { console.log('Componente montado') })
// Exponer al template return { count, message, doubleCount, increment } }}</script>Ventajas de <script setup>
Section titled “Ventajas de <script setup>”- Menos código repetitivo: No es necesario devolver explícitamente las variables y funciones
- Mejor rendimiento: La compilación es más eficiente
- Mejor inferencia de tipos: Mejor soporte para TypeScript
- Más legible: Estructura más clara y directa
Macros de compilación
Section titled “Macros de compilación”En <script setup> se utilizan macros especiales para definir props, emits, etc.:
<script setup>// Propsconst props = defineProps({title: String,likes: { type: Number, default: 0 }})
// Eventosconst emit = defineEmits(['update', 'delete'])
// Exponer propiedades/métodos al componente padredefineExpose({submit() { // ...}})</script>El bloque <style> contiene los estilos CSS del componente. Vue permite estilos encapsulados con el atributo scoped.
<style>/* Estilos globales */.button { background-color: #4CAF50; color: white; padding: 10px 20px; border: none; border-radius: 4px; cursor: pointer;}</style><style scoped>/* Estilos encapsulados al componente */.button { background-color: #4CAF50; color: white; padding: 10px 20px; border: none; border-radius: 4px; cursor: pointer;}</style><style lang="scss" scoped>$primary-color: #4CAF50;
.button { background-color: $primary-color; color: white; padding: 10px 20px; border: none; border-radius: 4px; cursor: pointer;
&:hover { background-color: darken($primary-color, 10%); }}</style>CSS Modules
Section titled “CSS Modules”Vue también soporta CSS Modules:
<template> <button :class="$style.button">Click me</button></template>
<style module>.button { background-color: #4CAF50; color: white;}</style>Tipado con lang=“ts”
Section titled “Tipado con lang=“ts””Vue 3 ofrece excelente soporte para TypeScript. Para usar TypeScript en un componente, se agrega el atributo lang="ts" al bloque <script>.
<script setup lang="ts">import { ref, computed } from 'vue'
// Interfaces y tiposinterface User {id: numbername: stringemail: stringactive: boolean}
// Variables tipadasconst count = ref<number>(0)const user = ref<User>({id: 1,name: 'John Doe',email: 'john@example.com',active: true})
// Props tipadasconst props = defineProps<{title: stringitems: Array<{ id: number, text: string }>callback?: (id: number) => void}>()
// Emits tipadosconst emit = defineEmits<{(e: 'update', id: number, value: string): void(e: 'select', item: { id: number, text: string }): void}>()
// Funciones tipadasfunction processUser(user: User): boolean {return user.active}</script>Definición de props con valores por defecto
Section titled “Definición de props con valores por defecto”En TypeScript, se puede usar withDefaults para definir valores por defecto para props tipadas:
interface Props { title?: string count?: number}
const props = withDefaults(defineProps<Props>(), { title: 'Untitled', count: 0})Importación y uso de componentes
Section titled “Importación y uso de componentes”En Vue 3 con <script setup>, los componentes importados se registran automáticamente.
<script setup>// Importación de componentesimport BaseButton from './BaseButton.vue'import BaseInput from './BaseInput.vue'import { SearchBox, FilterMenu } from './SearchComponents'
// Los componentes importados están disponibles automáticamente en el template</script>
<template><div> <BaseInput v-model="searchQuery" /> <BaseButton @click="search">Buscar</BaseButton>
<SearchBox /> <FilterMenu :options="filterOptions" /></div></template>Importación dinámica (Lazy Loading)
Section titled “Importación dinámica (Lazy Loading)”Para componentes grandes o que no son necesarios inmediatamente, se puede usar importación dinámica:
<script setup>import { defineAsyncComponent } from 'vue'
const HeavyComponent = defineAsyncComponent(() => import('./HeavyComponent.vue'))</script>
<template> <HeavyComponent v-if="showHeavyComponent" /></template>Componentes globales vs. locales
Section titled “Componentes globales vs. locales”import { createApp } from 'vue'import App from './App.vue'import BaseButton from './components/BaseButton.vue'import BaseInput from './components/BaseInput.vue'
const app = createApp(App)
// Registro global (disponible en toda la aplicación)app.component('BaseButton', BaseButton)app.component('BaseInput', BaseInput)
app.mount('#app')<script setup>// Registro local (solo disponible en este componente)import BaseButton from './components/BaseButton.vue'import BaseInput from './components/BaseInput.vue'</script>