Cada componente se define como un archivo .vue, independientemente de si el componente es una vista, o una parte de esta. Disponemos de dos formas de construir nuestros componentes, que vamos a ver a continuación.
La estructura básica de un componente es la siguiente:
<template>
<!-- Bloque HTML -->
</template>
<script>
export default {
// Funcionalidad Javascript
};
</script>
<style scoped>
// Estilos CSS del componente
</style>
<i18n>
// Internacionalización
</i18n> |
Como podemos ver, estos archivos se dividen en diferentes bloques. En este caso vemos tres, pero hay alguno más que podemos incluir.
En el bloque template se incluye el código HTML del código. Se trata de HTML enriquecido, pues podremos referenciar a variables y métodos definidos en la parte JavaScript del componente. Hay que tener en cuenta que sólo puede haber un componente HTML en el primer nivel. Por ejemplo, teniendo todo lo que contenga envuelto en un div. Vamos a ver la sintaxis de las funciones que nos ofrece este HTML enriquecido.
Para mostrar variables definidas en el bloque de script en el texto, lo haremos entre dobles corchetes:
<span>Mensaje: {{ msg }}</span> |
Además podemos enlazar variables a propiedades de los componentes que se instancian con v-bind, o simplemente con dos puntos:
<fwjsHeader :title="titulo" /> <fwjsHeader v-bind:title="titulo" /> |
Para enlazar variables en formularios, disponemos de v-model. Esto nos servirá con componentes input, textarea y select, y enlazará la variable bidireccionalmente a la propiedad "value" del componente:
<input v-model="nombre" /> |
Podemos hacer el manejo de eventos con v-on, o con @. Con esto establecemos un listener para dicho evento, y le indicamos el código JavaScript a ejecutar cuando ocurra dicho evento. Podemos indicar una línea de código simple, o una función que hayamos definido en el bloque script:
<button v-on:click="counter += 1">Add 1</button> <button @click="counter += 1">Add 1</button> |
El bloque script contiene la funcionalidad JavaScript del componente, pudiendo definir tanto variables propias como métodos, así como modificar el funcionamiento del propio componente. Para entender cómo funcionan los componentes, y cómo modificar su comportamiento, tenemos que conocer su ciclo de vida:

En este diagrama podemos ver los diferentes pasos que se siguen, y podemos ver que antes y después de los diferentes estados salen en rojo, señalados con una línea de puntos, nombres de funciones. Estas funciones son las llamadas lifecycle hooks, y nos permiten ejecutar código en esos momentos. Esto nos puede ser útil, por ejemplo, para cargar algún valor llamando a un servicio REST antes de que se monte el componente. Para definir estos métodos, lo haremos dentro del bloque script, y dentro del export default { ... }.
A partir de aquí, tenemos que diferenciar entre dos formas de organizar el bloque script, Options API y Composition API. Options API es la forma tradicional de organizar los componentes, la que ya utilizábamos en Vue 2 y que sigue estando disponible en Vue 3. A continuación vamos a ver cada una de ellas, a partir de aquí porque los lifecycle hooks ya se nombran de forma diferente.
Las diferentes opciones, aunque podemos verlas también en el diagrama, son:
beforeCreate() { ... }created() { ... }beforeMount() { ... }mounted() { ... }beforeUpdate() { ... }upadated() { ... }beforeDestroy() { ... }destroyed() { ... }Además de definir estos métodos, dentro del export default { ... } también podemos definir los siguientes campos:

name: nombre del componente. Si no lo definimos, por defecto será el del archivo.props: variables que se le pasarán como parámetro en el template.data(): variables definidas internamente en el propio componente, con alcance local.computed(): variables calculadas.methods: métodos definidos en el componente.watch: listeners, funciones que se ejecutarán cuando el valor de la variable que indiquemos que se observa cambie.components: otros componentes que se usan en el template. Para registrar componentes localmente.emits: lista de eventos personalizados que pueden ser emitidos desde el componente con la sintaxis this.$emit("name", value).
Antes del export default { ... } se pueden importar otros componentes para registrarlos localmente, o archivos JavaScript para utilizar su funcionalidad. Hay una página de documentación dedicada a cómo registrar componentes.
Un ejemplo de lo que hemos ido listando para el bloque script puede ser este:
<script>
import OtroComponente from './OtroComponente.vue';
export default {
name: Componente,
props: ['prop1', 'prop2'],
data() {
return {
mensaje: "Hola"
}
},
computed: {
mensajeAlReves: function() {
return this.mensaje.reverse();
}
},
methods: {
hacerCosas() {
// Código js
}
},
watch: {
mensaje: function(newValue, oldValue) {
console.log("El mensaje ha cambiado de '" + oldValue + "' a '" + newValue + "'");
}
},
emits: ["algo", "otroEvento"],
components: {
OtroComponente
},
beforeCreate() {},
created() {},
beforeMount() {},
mounted() {},
beforeUpdate() {},
updated() {},
beforeDestroy() {},
destroyed() {}
}
</script> |
Composition API es una forma de organizar los componentes que permite una mayor flexibilidad a la hora de organizar el código y una mayor reusabilidad de éste. Ahora en lugar de la estructura:
<script>
export default {
...
}
</script> |
Tendremos:
<script setup>
...
</script> |
Vamos a ir viendo las cosas que se utilizan de forma diferente:
En lugar de en un bloque props, lo haremos así:
<script setup>
const props = defineProps({
foo: String
})
const emit = defineEmits(['change', 'delete'])
...
</script> |
En progreso |
Los bloques style incluyen estilos css. En este caso, se pueden tener varios bloques style:
<styles>: estilos globales, se aplicarán a todo el proyecto.<styles scoped>: se aplica sólo al componente. Estos no se aplican tampoco a componentes hijos, para eso podemos utilizar ::v-deep, de esta forma:
<style scoped>
#tabla-asignaturas ::v-deep .p-datatable-tbody tr td {
border: none !important;
}
#tabla-asignaturas ::v-deep .p-datatable-row {
vertical-align: top;
}
</style> |
En la página de documentación de internacionalización podemos ver cómo incluir un bloque para especificar las cadenas de texto y sus traducciones en el propio componente.