...
Como podemos ver, estos archivos se dividen en diferentes bloques. En este caso vemos tres, pero hay alguno más que podemos incluir.
Template: código HTML
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.
...
| Bloque de código | ||
|---|---|---|
| ||
<button v-on:click="counter += 1">Add 1</button> <button @click="counter += 1">Add 1</button> |
Script
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:
...
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.
Options API
Las diferentes opciones, aunque podemos verlas también en el diagrama, son:
...
| Bloque de código | ||
|---|---|---|
| ||
<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
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:
...
Vamos a ir viendo las cosas que se utilizan de forma diferente:
Lifecycle hooks
Los lifecycle hooks, en Composition API, tenemos que importarlos de vue, y definirlos de esta forma:
...
| Options API | Composition API | Descripción |
|---|---|---|
| beforeCreate | - | Se escribe directamente en el setup |
| created | - | Se escribe directamente en el setup |
| beforeMount | onBeforeMount | Se ejecuta justo antes de que se monte el componente. |
| mounted | onMounted | Se ejecuta una vez se ha montado el componente. |
| beforeUpdate | onBeforeUpdate | Se ejecuta antes de una actualización del DOM. |
| updated | onUpdated | Se ejecuta cada vez que se actualiza el DOM por un cambio de estado reactivo. |
| beforeUnmount | onBeforeUnmount | Se ejecuta antes de quitar el componente. |
| unmounted | onUnmounted | Se ejecuta una vez se ha quitado el componente. |
Props y emits
En lugar de en un bloque props, lo haremos así:
| Bloque de código | ||
|---|---|---|
| ||
<script setup>
const props = defineProps({
foo: String
})
const emit = defineEmits(['change', 'delete'])
...
</script> |
ref() y reactive(): variables del componente
Mientras que antes teníamos que definir las variables reactivas del componente dentro del bloque data, ahora podemos definirlas con dos métodos, ref() y reactive(). Las variables que definamos con éstos, como decimos, serán reactivas, es decir, el template se enterará de los cambios en estas variables, reaccionará a ellos. Una variable definida de manera normal no será reactiva, el DOM no se actualizará cuando su valor cambie. Para utilizarlo, tenemos que importarlos primero, y se utilizan así:
...
Estas son las opciones que tenemos, pero realmente podemos utilizar ref() para todo. Pues permite lo mismo que reactive y más (valores primitivos, reemplazar objeto), y el uso de .value hará que seamos conscientes siempre de que estamos trabajando con una variable que es reactiva para el template, de modo que tengamos una diferenciación entre estas variables y las variables normales, y tratemos con ellas siempre del mismo modo.
Computed
Para las variables computadas, disponemos de la función computed(). Cada una la definiremos así:
| Bloque de código | ||
|---|---|---|
| ||
const color = computed(() => {
if(contador.value < 0){
return 'red'
}else{
return 'blue'
}
}) |
Watchers
Para reaccionar a cambios en variables que requieran algo más complejo que un computed, disponemos de watch(). A esta, se le especifica la variable a observar, y una función cuyos parámetros son el valor anterior y el nuevo.
...
Esto, con valores primitivos es bastante simple, pero se puede complicar para valores complejos. Mientras no tengamos documentado esto, podéis mirar esta guía, que es bastante completa: https://www.netlify.com/blog/2021/01/29/deep-dive-into-the-vue-composition-apis-watch-method/
Métodos
Como con la sintaxis que estamos utilizando, se están exponiendo al template las variables y métodos que utilizamos, podemos definir lo que antes teníamos dentro de methods como funciones normales:
...
| Bloque de código | ||
|---|---|---|
| ||
<script setup>
import { useMouse } from './mouse.js'
const { x, y } = useMouse()
</script>
<template>Mouse position is at: {{ x }}, {{ y }}</template> |
Emit: emitir eventos
Para que nuestro componente lance eventos, devemos definir los que puede lanzar con defineEmits(), y después podremos lanzarlos directamente con emit():
| Bloque de código | ||
|---|---|---|
| ||
<script setup>
const emit = defineEmits(['eventA', 'eventB'])
function btnClick(params) {
emit('eventA')
emit('eventB', params)
}
</script> |
Importar componentes
Para registrar componentes de forma local, es decir, en otros componentes, en Composition API vale simplemente con importarlos:
| Bloque de código | ||
|---|---|---|
| ||
<template>
<MyComponent />
</template>
<script setup>
import MyComponent from './MyComponent.vue'
</script> |
Sin embargo, en Options API, tenemos que importarlos y añadirlos al bloque components:
| Bloque de código | ||
|---|---|---|
| ||
<template>
<MyComponent />
</template>
<script setup>
import MyComponent from './MyComponent.vue'
export default {
components: {
MyComponent,
}
}
</script> |
También se pueden registrar componentes de forma global, para que estén disponibles desde todos los componentes del proyecto, pero esto no lo haremos, pues tenemos un sólo proyecto para todos los servicios del Portal de Servicios.
Style
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:Bloque de código language css <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>
i18n
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.