, ,

Tuto Nuxt3, Chapitre 3 : Programmation (variables, v-if, v-for…)

Article précédent : Chapitre 2 : Pages et composants
Vous pouvez commencer ce chapitre avec les sources suivantes : https://github.com/undevweb/un-tuto-nuxt-3/releases/tag/chapitre-2-pages-et-composants

Variables

Vous l’avez peut ĂȘtre remarquĂ©, dans chacun des composants il y avait la balise

Vue
<script setup lang="ts">
</script>

Celle ci n’Ă©tait pas obligatoire, surtout qu’elle Ă©tait vide. Nous allons Ă  prĂ©sent nous en servir pour y coder des fonctions et utiliser des variables.

  • Editez le fichier pages/articles.vue
pages/articles.vue
<template>
  <div id="articles">
    <h1>Articles (Total : {{ nbArticles }} )</h1>

    <ArticleSummary>
      <template #animal-name>{{ animalName  }} ({{ animalName .length }} lettres)</template>
      <template #animal-description>{{ animalDescription  }}</template>
    </ArticleSummary>

    <a href="/">Revenir Ă  l'accueil</a>
  </div>
</template>
<script setup lang="ts">
  const nbArticles = ref(1);
  const animalName = ref('Le Narval : La Licorne des Mers');
  const animalDescription = ref('Le narval, souvent surnommĂ© la « licorne des mers », est un cĂ©tacĂ© que l\'on trouve dans les eaux arctiques. Les mĂąles sont facilement reconnaissables grĂące Ă  leur longue dĂ©fense torsadĂ©e, qui est en rĂ©alitĂ© une canine. Cette dĂ©fense peut mesurer jusqu’à trois mĂštres de long. Le narval est un animal mystĂ©rieux, et ses habitudes de vie restent encore peu connues. Ils se nourrissent principalement de poissons, de crevettes et de calamars, et vivent en petits groupes.');
</script>

Nous voyons dans la balise script que nous avons créé 3 variables. En nuxt, on utilise ref pour indiquer que celles ci vont ĂȘtre rĂ©actives : si leur valeur change alors elles changeront dans le dom.
Les ref peuvent accueillir n’importe quel type natif de typescript (number, string, boolean…).

Dans le dom on peut afficher ces variables oĂč l’on veut en les englobant par des doubles accolades {{}}
Les {{}} sont en rĂ©alitĂ© un retour de string typescript. C’est Ă  dire qu’il est tout Ă  fait possible de coder ceci : {{ ‘Description de l’animal : ‘ + animalDescription }} ou comme dans notre fichier une fonction de string avec {{ animalName.length }}.

C’est rĂ©actif donc ajoutons un moyen de modifier les valeurs :

  • Editez le fichier pages/articles.vue
pages/articles.vue
<template>
  <div id="articles">
    <h1>Articles (Total : {{ nbArticles }} )</h1>

    <ArticleSummary>
      <template #animal-name>{{ animal.name }} ({{ animal.name.length }} lettres)</template>
      <template #animal-description>{{ animal.description }}</template>
    </ArticleSummary>

    <form>
      <p>
        <label for="name">Nom : </label>
        <input id="name" v-model="animalName" width="400">
      </p>
      <p>
        <label for="description">Description : </label>
        <textarea id="description" v-model="animalDescription" cols="100" rows="5"></textarea>
      </p>
    </form>
    
    <a href="/">Revenir Ă  l'accueil</a>
  </div>
</template>
<script setup lang="ts">
  const nbArticles = ref(1);
  const animalName = ref('Le Narval : La Licorne des Mers');
  const animalDescription = ref('Le narval, souvent surnommĂ© la « licorne des mers », est un cĂ©tacĂ© que l\'on trouve dans les eaux arctiques. Les mĂąles sont facilement reconnaissables grĂące Ă  leur longue dĂ©fense torsadĂ©e, qui est en rĂ©alitĂ© une canine. Cette dĂ©fense peut mesurer jusqu’à trois mĂštres de long. Le narval est un animal mystĂ©rieux, et ses habitudes de vie restent encore peu connues. Ils se nourrissent principalement de poissons, de crevettes et de calamars, et vivent en petits groupes.');
</script>

v-model permet de lier un champ de formulaire à une variable réactive. Ainsi sur http://localhost:3001/articles vous pouvez éditer les champs Nom et Description et constater que cela change dynamiquement dans le summary !

En bon dĂ©veloppeur de POO, on voit que animal devrait plutĂŽt ĂȘtre un objet. Comme on est en typescript, on peut mĂȘme crĂ©er une interface et dĂ©clarer Ă  ref le type attendu. Profitons en pour ajouter les propriĂ©tĂ©s height et weight au passage en les rendant facultative.

  • A la racine, crĂ©ez le dossier utils
  • CrĂ©ez le dossier utils/interfaces
  • CrĂ©ez le fichier utils/interfaces/animal.interface.ts
utils/interfaces/animal.interface.ts
export interface AnimalInterface {
    name: string;
    description: string;
    height?: number;
    weight?: number;
}
  • Editez le fichier pages/articles.vue
Vue
<template>
  <div id="articles">
    <h1>Articles (Total : {{ nbArticles }} )</h1>

    <ArticleSummary>
      <template #animal-name>{{ animal.name }} ({{ animal.name.length }} lettres)</template>
      <template #animal-height>{{ animal.height }}</template>
      <template #animal-weight>{{ animal.weight}}</template>
      <template #animal-description>{{ animal.description }}</template>
    </ArticleSummary>

    <form id="form-article-update">
      <p>
        <label for="name">Nom : </label>
        <input id="name" v-model="animal.name" width="400">
      </p>
      <p>
        <label for="height">Hauteur : </label>
        <input type="number" id="height" v-model="animal.height" min="0"></input>
      </p>
      <p>
        <label for="weight">Poids : </label>
        <input type="number" id="weight" v-model="animal.weight" min="0"></input>
      </p>
      <p>
        <label for="description">Description : </label>
        <textarea id="description" v-model="animal.description" cols="100" rows="5"></textarea>
      </p>
    </form>

    <a href="/">Revenir Ă  l'accueil</a>
  </div>
</template>
<script setup lang="ts">
import type {AnimalInterface} from '~/utils/interfaces/animal.interface';

const nbArticles = ref(1);
const animal = ref<AnimalInterface>({
  name: "",
  description: ""
});
</script>

Les éléments important à comprendre dans cette étape :
– on peut utiliser la variable en tant qu’objet dans le dom : {{ animal.name }} va afficher le nom de l’animal
v-model= »animal.height » et autre v-model utilisent Ă©galement l’objet en tant que tel
const animal = ref<AnimalInterface>, la variable s’appelle bien animal et est un objet dont les valeurs facultative n’ont pas Ă©tĂ© initialisĂ©es (elles peuvent l’ĂȘtre si on le souhaite. la partie entre chevrons est de la gĂ©nĂ©ricitĂ©, cela permet d’indiquer Ă  ref quel sera le type attendu.

C’est un choix personnel de dĂ©clarer le type Ă  ref, avec nuxt vous n’ĂȘtes pas obligĂ©s de le faire et aurez trĂšs bien pu Ă©crire :

Vue
<script setup lang="ts">
const animal = ref({
  name: "",
  description: ""
});
</script>

Utiliser l’interface permet de limiter les erreurs et une meilleure autocomplĂ©tion avec les bons IDEs.

v-if

Avec nuxt on peut utiliser v-if pour afficher ou non un bloc en fonction d’un boolean.

Si l’on veut afficher le text « grand » pour les animaux qui dĂ©passent 200 cm il suffit d’Ă©crire !

Vue
<span v-if="animal.height && animal.height > 200" class="badge">Grand</span>

(Rappelons que height n’est pas obligatoire d’oĂč le &&)

Le v-if marche aussi bien avec des balise inline que bloc et mĂȘme sur des composant. On peut donc ajouter un v-if= »animal.name » sur la balise <ArticleSummary> pour ne pas afficher tant qu’il n’y a pas de nom.

Vue
<ArticleSummary v-if="animal.name">

Pour info, v-show existe aussi. La diffĂ©rence est que v-show va charger l’intĂ©rieur et le masquer lĂ  ou v-if ne charge pas si la condition n’est pas vraie.

Computed

Les computed sont des variables calculées. On peut par utiliser une compûted à la place de animal.height && animal.height > 200.

Vue
<script setup lang="ts">
// ... 
const isTall = computed(() => animal.value.height && animal.value.height > 200);
// ... 
</script>

Vous noterez le .value . ref est un objet donc quand on l’utilise au sein de <script> il faut utiliser .value y compris si on change sa valeur via une fonction :
animal.value.height = 158;

On a dĂ©clarĂ© isTall et indiquĂ© que sa valeur dĂ©pend du rĂ©sultat de la fonction flĂ©chĂ©e. On peut donc l’utiliser dans le v-if :

Vue
<span v-if="isTall" class="badge">Grand</span>

Ceci rend la lecture du dom plus lisible.

v-for

v-for permet de boucler sur un array dans le dom. Ici nous voudrons afficher le nom de tous les animaux que l’on a dans une liste d’articles :

Vue
<template>
    <ul>
      <li v-for="animal of articles" :key="`animal-${animal.name}`">
        {{ animal.name }}
      </li>
    </ul>
</template>
<script setup lang="ts">
const articles = ref([
  {
    name: "Le Fennec : Renard du Désert"
  },
  {
    name: "Le Panda Roux : Une EspĂšce en Danger"
  },
  {
    name: "L’Axolotl : Le petit monstre tout mignon d'Eau Mexicain"
  }
]);
</script>

:key= est trÚs important pour le fonctionnement interne de nuxt. Cela lui permet de plus facilement identifier un noeud et améliore grandement les performances.

Ici nous avons bouclĂ© sur la balise <li>. Cela signifie qu’il y aura un <li> par article.

v-for peut ĂȘtre utilisĂ© sur des balises inline, bloc et sur des composants. Tout ce qui est Ă  l’intĂ©rieur du v-for sera pris en compte :

Vue
<template>
    <div id="articles">
      <div v-for="animal of articles" :key="`animal-${animal.name}`">
        <p>{{ animal.name }}</p>
        <p>{{ animal.height }}</p>
      </div>
    </div>
</template>
<script setup lang="ts">
const articles = ref([
  {
    name: "Le Fennec : Renard du Désert",
    height: 35
  },
  {
    name: "Le Panda Roux : Une EspĂšce en Danger",
    height: 60,
  },
  {
    name: "L’Axolotl : Le petit monstre tout mignon d'Eau Mexicain",
    height: 17.5,
  }
]);
</script>

Nous allons dans notre blog l’utiliser sur le composant summary pour afficher un summary par article. Profitons en pour sĂ©parer notre page en 2 avec en haut la liste des articles et en bas l’ajout d’un article.

  • Editez le fichier pages/articles.vue
pages/articles.vue
<template>
  <div id="articles">
    <h1>Articles (Total : {{ articles.length }} )</h1>

    <div class="articles-grid">
      <ArticleSummary v-for="animal of articles" :key="`animal-${animal.name}`">
        <template #animal-name>{{ animal.name }} ({{ animal.name.length }} lettres) <span v-if="isTall" class="badge">Grand</span></template>
        <template #animal-height>{{ animal.height }}</template>
        <template #animal-weight>{{ animal.weight }}</template>
        <template #animal-description>{{ animal.description }}</template>
      </ArticleSummary>
    </div>

    <h1>Ajouter un article</h1>

    <ArticleSummary v-if="animal.name">
      <template #animal-name>{{ animal.name }} ({{ animal.name.length }} lettres) <span v-if="isTall" class="badge">Grand</span></template>
      <template #animal-height>{{ animal.height }}</template>
      <template #animal-weight>{{ animal.weight }}</template>
      <template #animal-description>{{ animal.description }}</template>
    </ArticleSummary>

    <form id="form-article-update">
      <p>
        <label for="name">Nom : </label>
        <input id="name" v-model="animal.name" width="400">
      </p>
      <p>
        <label for="height">Hauteur : </label>
        <input type="number" id="height" v-model="animal.height" min="0"></input>
      </p>
      <p>
        <label for="weight">Poids : </label>
        <input type="number" id="weight" v-model="animal.weight" min="0"></input>
      </p>
      <p>
        <label for="description">Description : </label>
        <textarea id="description" v-model="animal.description" cols="100" rows="5"></textarea>
      </p>
    </form>

    <a href="/">Revenir Ă  l'accueil</a>
  </div>
</template>
<script setup lang="ts">
import type {AnimalInterface} from '~/utils/interfaces/animal.interface';

const nbArticles = ref(1);
const animal = ref<AnimalInterface>({
  name: "",
  description: ""
});
const isTall = computed(() => animal.value.height && animal.value.height > 200);
const articles = ref<AnimalInterface[]>([
  {
    name: "Le Fennec : Renard du Désert",
    height: 35,
    weight : 1,
    description: "Le fennec est un petit renard vivant dans les dĂ©serts d'Afrique du Nord. Il est facilement identifiable grĂące Ă  ses grandes oreilles, qui lui permettent de rĂ©guler la tempĂ©rature de son corps et d’entendre les proies se dĂ©placer sous le sable. Ce nocturne est parfaitement adaptĂ© Ă  son environnement aride : il peut survivre de longues pĂ©riodes sans boire d’eau, car il obtient toute l’humiditĂ© nĂ©cessaire de la nourriture qu'il consomme, comme des insectes, des rongeurs et des plantes."
  },
  {
    name: "Le Panda Roux : Une EspĂšce en Danger",
    height: 60,
    weight : 4.5,
    description: "Le panda roux est un petit mammifĂšre vivant dans les forĂȘts montagneuses de l'Himalaya et du sud-ouest de la Chine. Bien qu’il partage une partie de son nom avec le panda gĂ©ant, ces deux espĂšces ne sont pas Ă©troitement liĂ©es. Le panda roux est un grimpeur agile et passe une grande partie de son temps dans les arbres, oĂč il mange principalement des bambous, mais aussi des fruits, des insectes et des Ɠufs. Avec son pelage roux et sa queue touffue, il est extrĂȘmement mignon, mais aussi menacĂ© par la dĂ©forestation."
  },
  {
    name: "L’Axolotl : Le petit monstre tout mignon d'Eau Mexicain",
    height: 17.5,
    weight : 0.130,
    description: "L'axolotl est un amphibien originaire des lacs du Mexique, principalement le lac Xochimilco. Ce petit animal est fascinant pour sa capacitĂ© Ă  rĂ©gĂ©nĂ©rer ses membres, ses organes et mĂȘme des parties de son cerveau. Contrairement Ă  la plupart des amphibiens, l'axolotl reste Ă  l’état larvaire toute sa vie, conservant ses branchies externes et vivant exclusivement sous l'eau. Il se nourrit de petits poissons, de vers et d'insectes aquatiques. Cependant, Ă  cause de la pollution et de la destruction de son habitat, il est aujourd'hui gravement menacĂ©."
  }
]);
</script>
<style scoped lang="css">
.badge{
  background: #4CAF50;
  font-weight: bold;
  border-radius: 15px;
  border: 1px solid #555555;
  padding: 4px;
  text-align: center;
  font-size: 9pt;
}

.articles-grid {
  display: flex;
  justify-content: space-between;
}
</style>

You might also like