Versiones comparadas

Clave

  • Se ha añadido esta línea.
  • Se ha eliminado esta línea.
  • El formato se ha cambiado.

...

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
languagexml
<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 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
languagejs
<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 APIComposition APIDescripción
beforeCreate-Se escribe directamente en el setup
created-Se escribe directamente en el setup
beforeMountonBeforeMountSe ejecuta justo antes de que se monte el componente.
mountedonMountedSe ejecuta una vez se ha montado el componente.
beforeUpdateonBeforeUpdateSe ejecuta antes de una actualización del DOM.
updatedonUpdatedSe ejecuta cada vez que se actualiza el DOM por un cambio de estado reactivo.
beforeUnmountonBeforeUnmountSe ejecuta antes de quitar el componente.
unmountedonUnmountedSe 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
languagejs
<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
languagejs
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
languagejs
<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
languagejs
<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
languagejs
<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
languagejs
<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
    languagecss
    <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.