Imprimer
Catégorie : R3.01 - dev. Web côté client (vuejs)
Affichages : 24
Préambule
 

 

1°/ Principes de vuejs

 

 

 

 

2°/ Description d'un fichier SFC pour vuejs (extension .vue)

2.1°/ Structuration générale

<template>
    <!-- visuel du composant, en HTML + directive vuejs -->
</template>

<script setup>
    // modèle des données et du contrôle du composant, écrit en JS
</script>

<style>
    // définition des styles CSS
</style>

 

 

 2.2°/ partie <script>

IMPORTANT :

 

<script setup>
// importation de modules/fonctions/objets/...

// définition des variables locales, avec ref/reactive/...

// définition des "props"

// définition des variables "computed"

// définition des fonctions normales

// définition des watchers

// définition des "hook" (onMounted, ...)

</script>

 Remarques :

 

2.2.1°/ imports

import {ref, computed} from "vue"
import MonComp from '@/components/MyCompo.vue'

 

2.2.2°/ variables locales

 

ATTENTION : quelle que soit la fonction utilisée, une variable contenant un tableau doit être manipulée via les fonctions de la classe Array : push(), splice(), ... Sinon, vuejs ne verra pas le changement du contenu du tableau et il n'y aura pas de réactivité.

<template>
  {{ val }}
  {{ perso }}
  ...
</template>
  
<script setup>
  ...
  const val = ref(10)
  const perso = reactive({name:"toto", age: 20})
  const tabref = ref([])
  const tabreac = reactive([])
  ...
  val = 5 // INCORRECT
  val.value = 5 // OK
  perso.name = "tutu" //OK
  perso.age = 21 // OK
  tabref.value[0] = 3 // PAS REACTIF
  tabref.value.push(2) // OK
  tabreac.push(2) // OK
  ...
<script>

 

2.2.3°/ props

 ATTENTION : on ne doit JAMAIS modifier directement la valeur d'une props, par exemple dans une fonction, un watcher, ...

Exemple :

<template>
  {{ title }}
</template>
<script setup>
  const props = defineProps({
    title: String
  })
  console.log(props.title)
  ...
</script>

 

2.2.4°/ variable computed

 

<script setup>
  ...
  const idx = ref(0)
  const tab = ref([])
  ...
  const idxSafe = computed( () => { if ((idx.value<0) || (idx.value >= tab.value.length)) return 0; return idx.value } )
  const getval = computed( () => index => tab.value[index] )
  ...
  console.log(getval.value(10))
</script>

 

Explication : la fonction associée à getval() renvoie une fonction avec un paramètre. Écrire getval.value permet de récupérer cette fonction, et donc getval.value(...) d'appeler cette fonction. 

 

2.2.5°/ méthodes "normales"

<script setup>
  ...
  function maFct(val, msg) {
    ...
  }
  ...
<script>

 

2.2.6°/ watchers

Exemple :

<script setup>
  ...
  const val = ref(0)
  ...
  watch( val, (newVal) => { if (newVal<0) alert("valeur positive") } )
  ...
</script>

 

 

2.2.7°/ hooks

Exemple :

<script setup>
  ...
  onMounted( () => console.log("mounted") )
  onUpdated( () => console.log("updated") )
  ...
</script>

  

3°/ Exemple illustratif (avec spoiler sur les directives vuejs)

 

ATTENTION ! Cet exemple permet juste d'illustrer les différents points abordés précédemment, dans un but pédagogique. En pratique, on n'écrirait pas un tel composant de cette façon, mais plus simplement (par ex, pas besoin de watcher, ni de mounted() ).


 Télécharger les sources : [ vuejs-td1-src.tgz ]

NB : cette archive contient uniquement le répertoire src. Il faut donc au préalable créer un projet basique avec vue-cli puis remplacer le répertoire src par celui contenu dans l'archive.


Dans model.js, on a :

var gamers = [ {name: 'jean', pseudo: 'jj'}, {name: 'pierre', pseudo: 'pepe'} ]
export {gamers}

 Dans MyComponentV3.vue, on a :

<template>
  <div>
    <h1>{{ title }}</h1>
    <p>Il y a actuellement {{ nbGamers }} joueurs </p>
    <select v-model="idSelected">
      <option v-for="(gamer,index) in gamersList" :key="index" :value="index">{{gamer.name}}</option>
    </select>
    <p v-if="currentGamer">pseudo joueur sélectionné : {{ currentGamer.pseudo }} </p>
    <hr>
    <input v-model="playerName"><input v-model="playerPseudo">
    <button @click="addPlayer">Ajouter joueur</button>
  </div>
</template>

<script setup>
import {gamers} from './model'
import {ref, computed, watch, onMounted} from "vue";

const props = defineProps({
  title: String
})
// pour accéder aux props, on utilise l'objet renvoyer par defineProps
console.log(props.title)

const gamersList = ref(gamers)
const currentGamer = ref(null) // normalement, devrait être computed (cf. commentaire ci-dessous)
const idSelected = ref(-1)
// pour pouvoir ajouter des joueurs
const playerName = ref("")
const playerPseudo = ref("")

const nbGamers = computed(() => gamersList.value.length) // si gamersList change de taille, nbGamers sera automatiquement recaculé

/* NB : normalement, on a pas besoin d'utiliser setCurrentGamer+watcher : il suffit d'utiliser une fonction computed
 qui "calcule" currentGamer en fonction de idSelected. Cela s'écrit :
  const currentGamer = computed(() => { if( (idSelected.value >= 0) && (idSelected.value < nbGamers.value) ) return gamersList.value[idSelected.value]; return null })
 */
function setCurrentGamer(idx) {
  if( (idx >= 0) && (idx < nbGamers.value) ) { // on accède à la variable locale calculée nbGamers
    currentGamer.value = gamersList.value[idx]
  }
}
watch( idSelected, (newVal) => {
  console.log("nouveau joueur sélectionné : "+newVal)
  setCurrentGamer(newVal);
})

function addPlayer() {
  // NB: si on essaie d'ajouter à gamers au lieu de gamersList => pas de réactivité donc comportement "bizarre"
  gamersList.value.push({
    name: playerName.value,
    pseudo: playerPseudo.value,
  })
}

// "hook" appelé lorsque le composant estmonté dans le DOM
onMounted(() => {
  console.log("MyComponentV3 est monté dans le DOM")
})

</script>

 

Principes de fonctionnement : 
  • les items de la liste déroulante sont créés dynamiquement en fonction des objets se trouvant dans le tableau local gamersList, dont le contenu est celui de la variable importée gamers.
  • grâce à la directive v-for, on peut parcourir les élément de ce tableau, en les comptant, pour créer des balises "en boucle".
  • dans le cas présent, le texte de chaque item est tiré de l'attribut name et la valeur correspondant à l'item sélectionné est l'indice dans le tableau.
  • grâce à la directive v-model, on indique à vuejs que la sélection de l'utilisateur doit mettre à jour la variable idSelected, qui prendra donc comme valeur un indice dans le tableau gamersList.
  • grâce à un watcher, on observe tout changement de la valeur de idSelected. Si c'est le cas, on appelle une méthode qui met à jour un objet nommé currentGamer, représentant le joueur sélectionné.
  • comme indiqué en commentaire, ce watcher est normalement inutile : on peut très bien calculer la valeur de currentGamer en fonction de idSelected, via le mécanisme de variable computed.
  • on remarque également l'utilisation d'une variable computed nbGamers pour contenir le nombre d'éléments dans gamersList. Si gamersList change, alors nbGamers sera réévaluée.
  • la fonction addPlayer() est appelée via le clic sur le bouton ajouter. On remarque qu'elle utilise bien la fonction push() pour modifier gamersList. NB: si on modifiait gamers, il n'y aurait pas de réactivité et la page, donc la liste déroulante ne serait pas mise à jour automatiquement.
  • onMounted() est utilisée pour afficher un message lors de l'intégration du composant dans le DOM.
  • enfin, on remarque l'utilisation d'une directive v-if, qui permet d'inclure de manière conditionnelle le paragraphe <p>