Toit-terrasseN NuxtPièce 4/8Débutant

Les composants

Découper l'interface en composants importés automatiquement, leur passer des données et charger les plus lourds à la demande.

Ce que tu vas apprendre

  • Créer un composant et l'utiliser sans import.
  • Comment Nuxt nomme les composants rangés dans des sous-dossiers.
  • Passer des données à un composant, et en recevoir.
  • Charger un composant seulement quand il sert, ou seulement dans le navigateur.

Un composant, sans import

Sur ta page de recettes, chaque recette s'affiche dans une carte. Tu crées le fichier app/components/CarteRecette.vue, et tu l'utilises directement dans n'importe quelle page :

app/pages/recettes/index.vue
<template>
  <CarteRecette titre="Crêpes" :duree="20" />
</template>

Avec Vue seul, il faudrait écrire import CarteRecette from '...'. Nuxt le fait pour toi, et n'inclut dans le site que les composants réellement utilisés.

Les sous-dossiers donnent le nom

Quand tu ranges un composant dans un sous-dossier, le nom du dossier devient le début du nom du composant :

FichierNom à utiliser
app/components/CarteRecette.vue<CarteRecette />
app/components/recette/Carte.vue<RecetteCarte />
app/components/recette/Ingredients.vue<RecetteIngredients />

Tu peux ainsi regrouper tous les composants d'une même partie du site, sans noms à rallonge dans les fichiers.

Passer des données : les props

Un composant reçoit des données de son parent par des props. Tu les déclares avec defineProps, et TypeScript vérifie que le parent envoie les bons types :

app/components/CarteRecette.vue
<script setup lang="ts">
const props = defineProps<{
  titre: string
  duree: number
  vegetarien?: boolean // le ? rend la prop facultative
}>()
</script>

<template>
  <article>
    <h2>{{ titre }}</h2>
    <p>{{ duree }} min <span v-if="vegetarien">· végétarien</span></p>
  </article>
</template>

Dans le parent, :duree="20" (avec les deux-points) envoie le nombre 20. Sans les deux-points, duree="20" enverrait le texte « 20 ».

Remonter une information : les événements

Les props descendent du parent vers l'enfant. Pour prévenir le parent (un clic sur « Ajouter aux favoris »), l'enfant émet un événement :

app/components/CarteRecette.vue
<script setup lang="ts">
const emit = defineEmits<{ favori: [id: number] }>()
</script>

<template>
  <button @click="emit('favori', 12)">Ajouter aux favoris</button>
</template>
<CarteRecette titre="Crêpes" :duree="20" @favori="ajouterFavori" />

Insérer du contenu : les slots

Un <slot /> laisse le parent glisser son propre contenu dans le composant. C'est le même mécanisme que pour les gabarits du chapitre précédent :

app/components/Encadre.vue
<template>
  <div class="encadre">
    <slot />
  </div>
</template>
<Encadre>Astuce : laisse reposer la pâte une heure.</Encadre>

Charger à la demande

Certains composants sont lourds (une carte, un éditeur) et ne servent pas tout de suite. Ajoute le préfixe Lazy devant le nom : leur code n'est téléchargé que lorsqu'ils s'affichent.

<script setup lang="ts">
const afficherCommentaires = ref(false)
</script>

<template>
  <button @click="afficherCommentaires = true">Voir les commentaires</button>
  <LazyRecetteCommentaires v-if="afficherCommentaires" />
</template>

Seulement dans le navigateur

Par défaut, Nuxt affiche aussi tes composants sur le serveur. Un composant qui utilise window ou localStorage plante alors, car ces objets n'existent que dans le navigateur. Deux solutions :

  • nommer le fichier avec .client.vue (par exemple Minuteur.client.vue) : il ne s'affiche que dans le navigateur ;
  • entourer le composant de <ClientOnly> dans le parent.
<ClientOnly>
  <Minuteur />
</ClientOnly>
Ce site s'en sert : les favoris sont lus dans le localStorage, donc le bouton favori est entouré de <ClientOnly>.

À retenir

  • Un fichier de app/components/ s'utilise sans import ; le sous-dossier préfixe le nom.
  • defineProps reçoit les données du parent, defineEmits lui envoie des événements, <slot /> accueille son contenu.
  • Lazy devant un nom charge le composant à la demande.
  • .client.vue ou <ClientOnly> pour un composant qui a besoin du navigateur.

Pour aller plus loin

Sources officielles

Ensuite

Projet
Lignes de code
Niveau
Toit-terrasse
Appartement
Nuxt
Pièce
4/8
Plan n°
nuxt/04.composants
Lignes de code · fiches rédigées à partir des documentations officielles, sources citées en bas de chaque page.