Open menu

1°/ Gestion des événements

1.1°/ mettre en place un écouteur : v-on

  • En JS basique, on met en place un écouteur d'événement sur une balise grâce aux attributs du type onXXX, par exemple onclick.
  • La valeur de cet attribut est généralement du code javascript simple, par exemple un appel à une fonction qui va gérer l'événement.
  • Vuejs propose la directive v-on pour obtenir le même résultat.
  • La différence est que v-on est paramétrable par le type d'événement que l'on veut écouter et que sa valeur est du javascript accédant directement aux données/méthodes (cf. ci-dessous) de l'instance de vue.

Démonstration :
  • créer un fichier index-01.js et copier/coller dedans :
 

 

  • créer un fichier model.js et copier/coller dedans :
 

 

  • créer un fichier exe-01.html et copier/coller dedans :
 
  • cliquer sur Buy : le montant d'or diminue ainsi que le premier item et le total acheté augmente Cela correspond aux traitements indiqués dans v-on.
  • cliquer dans le champ de saisie après "sell for", entrer une valeur, puis appuyer sur entrée. La valeur est crédité au montant d'or.

Remarques :

  • On ne peut pas mettre d'instructions de contrôle type if, for, ... dans v-on. On peut cepedant mettre une suite d'instructions simples séparées par des ;
  • On ne peut pas non plus utiliser des fonctions ou des données définies hors de l'instance de Vue. Par exemple, faire appel à alert() provoquerait une erreur.
  • Généralement, on préfère appeler une fonction qui contient ces instructions.
  • Il existe un raccourci d'écriture pour v-on:event => @event.
  • Quand un événement est déclenché, la variable vuejs $event est un objet représentant cet événement. Cela permet par exemple d'accéder à l'objet du DOM ayant déclenché l'événement, grâce à $event.target
  • Par exemple, dans @change, on récupère l'objet représentant la balise input et on va chercher sa valeur. Comme c'est une chaîne de caractère, on transforme en valeur numérique en faisant par exemple une division par 1, ou bine grâce à la fonction parseInt() (= plus propre)
  • En revanche, on ne peut pas utiliser if pour tester si ce montant est inférieur au montant acheté. Pour cela, il faut utiliser une fonction.

1.2°/ Gestion de la propagation des événements

  • Quand un événement a lieu sur une balise, il est possible que le navigateur ait un comportement par défaut qu'il applique quand bien même on appelle notre propre fonction de gestion de l'événement.
  • Par exemple, quand on clique sur une case à cocher, son visuel change en ajoutant/supprimant la croix à l'intérieur.
  • Parfois, ce comportement par défaut est une gêne et on désire l'empêcher. En JS, il suffit d'appeler la méthode preventDefault() de l'événement.
  • Une fois que l'événement est traité au niveau de la balise, il est propagé à la balise qui englobe la première. Si la seconde écoute l'événement, elle appelera également la fonction de gestion. Ainsi de suite en remontant jusqu'à <body>.
  • Cette propoagation est parfois génante et on désire l'empêcher. En JS, il suffit d'appeler la méthode stopPropagation() de l'événement.
  • Vuejs permet d'appeler ces méthodes automatiquement grâce à des "modificateurs" d'événements :
    • pour empêcher l'appel du gestionnaire par défaut, on ajoute .prevent derrière le nom de l'événement. Par exemple @click.prevent.
    • pour stopper la propagation à la balise parente, on ajoute .stop derrière le nom de l'événement. Par exemple @click.stop.
    • A noter que l'on peut les chaîner : @click.prevent.stop.
  • Il existe d'autres modificateurs, notamment ceux qui permettent de restreindre le déclenchement de l'événement à l'appui sur une/plusieurs touches (cf. API Vuels)


2°/ Les méthodes Vuejs



2.1°/ méthodes "basiques"
  • Une instance de Vue n'est forcément constituée d'un élément et de données. D'autres attributs peuvent être ajoutés, notamment methods, qui permet de créer des fonctions classiques.
  • Ces fonctions sont appelées soit en réponse à des événements, soit par d'autres fonctions.

Démonstration :
 
  • créer un fichier index-02.js et copier/coller dedans :
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
 var app = new Vue({
  el: '#mydiv',
  data: {
    gold : 3000,
    nbBought : 0,
    nbBoughtPrice : 0,
    canSellFor : 0,
    items
  },
  methods: {
    buy : function() {
      if (items[0].price <= this.gold) {
        this.nbBought+= 1;
        this.nbBoughtPrice += items[0].price;
        this.canSellFor += items[0].price;
        this.gold -= items[0].price;
 	items.splice(0,1);
      }
      else {
        alert('not engouh gold');
      }
    },
    sell: function(amount) {
      if (amount <= this.canSellFor) {
        this.gold += amount;
        this.canSellFor -= amount;
      }
      else {
        alert('amount overcome available');
      }
    }
  }
})
  • créer un fichier exe-02.html et copier/coller dedans :
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
<html>
<head>
  <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
  <script src="model.js"></script>
</head>
<body>
  <div id="mydiv">
    <ul>
      <li v-for="it in items">{{it.name}} : {{it.price}}</li>
    </ul>
    <button v-if="items.length>0" @click="buy">Buy first item</button>
    <p>bough items : {{nbBought}} for {{nbBoughtPrice}}</p>
    <p>gold : {{gold}}</p>
    <p>amount for sell : {{canSellFor}}</p>
    <label for="sell">sell for :</label><input id="sell" @change="sell(parseInt($event.target.value))">
  </div>
  <script src="index-02.js"></script>
</body>
</html>
  • Appuyez plusieur fois sur "Buy" : les différents montant changent.
  • Achetez jusqu'à ce que le message d'alerte s'affiche car il n'y a pas assez d'or.
  • Dans le champ "sell for", taper un montant supérieur à la valeur indiquée dasn "amount for sell" : un message d'alerte s'affiche. De même si vous tapez des lettres.
  • Tapez un montant inférieur : le montant d'or est recrédité.

Remarques :
  • FONDAMENTAL 1 : dans une méthode, toute propriété de data DOIT être référencée via this.nom_propriété. Sinon, on obtient des erreurs vuejs visibles dans la console de l'inspecteur.
  • FONDAMENTAL 2 : l'exception à la règle ci-dessus est quand un propriété observe un objet du modèle portant le même nom, par exemple items. Dans ce cas, utiliser this.items ou items est équivalent.
  • Quand on veut appeler une fonction sans paramètres, seul le nom de la fonction est nécessaire, par ex, buy.
  • Sinon, on fait un appel à la fonction comme en JS basique, par ex. sell(...).
  • Il est fréquent de créer des fonctions qui prennent en paramètre l'événement associé, par exemple @click="myfunc(value,$event)"


2.2°/ propriétés "calculées"
  • Quand la valeur de certaines variables de data sont uniquement obtenues grâce à un calcul, il est parfois possible de les supprimer de data et de créer une fonction de calcul portant leur nom, sans paramètres. Cette fonction doit être définie dans l'attribut computed de l'instance de vue.
  • On les appelle des propriétés calculées.
  • Leur valeur est recalculée chaque fois que la valeur d'une des variables/propriétés de la vue est utilisée pour le calcul change (=>  pas de mise à jour si le calcul n'utilse que des valeurs externes à la vue)
  • De ce fait, une propriété calculée peut l'être grâce à une autre. En revanche, elle ne peut pas être elle-même utilisée dans sa fonction de calcul.

Démonstration :
  • créer un fichier index-03.js et copier/coller dedans :
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
var app = new Vue({
  el: '#mydiv',
  data: {
    gold : 3000,
    nbBought : 0,
    nbBoughtPrice : 0,
    canSellFor : 0,
    items,
    numSel : 1
  },
  methods: {
    buy : function() {
      if (this.selectedItem.price <= this.gold) {
        this.nbBought+= 1;
        this.nbBoughtPrice += this.selectedItem.price;
        this.canSellFor += this.selectedItem.price;
        this.gold -= this.selectedItem.price;
        items.splice(this.numSel-1,1);
      }
      else {
        alert('not engouh gold');
      }
    },
    sell: function(amount) {
      if (amount <= this.canSellFor) {
        this.gold += amount;
        this.canSellFor -= amount;
      }
      else {
        alert('amount overcome available');
      }
    }
  },
  computed: {
    selectedItem : function() {
      return items[this.numSel-1];
    },
    itemName : function() {
      if (this.selectedItem != undefined)
        return this.selectedItem.name;
      return "no item";
    }
  }
})
  • créer un fichier exe-03.html et copier/coller dedans :
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
<html>
<head>
  <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
  <script src="model.js"></script>
</head>
<body>
  <div id="mydiv">
    <ol>
      <li v-for="it in items">{{it.name}} : {{it.price}}</li>
    </ol>
    <label for="select">#item :</label><input id="select" v-model="numSel">
    <button v-if="selectedItem" @click="buy">Buy {{itemName}}</button>
    <p>bough items : {{nbBought}} for {{nbBoughtPrice}}</p>
    <p>gold : {{gold}}</p>
    <p>amount for sell : {{canSellFor}}</p>
    <label for="sell">sell for :</label><input id="sell" @change="sell(parseInt($event.target.value))">    
  </div>
  <script src="index-03.js"></script>
</body>
</html>
  • changer la valeur dans le champ "#item" : le texte du bouton change, ou bien le bouton disparaît si l'on tape une valeur invalide. Normal, selectedItem prend la valeur undefined.


Remarques :
  • Dans cet exemple, itemName est juste utilisé pour illustrer une propriété calculée à partir d'une autre. En réalité, il suffit d'écrire Buy {{selectedItem.name}} pour le bouton.
  • Comme une proriété calculée ne prend pas de paramètres et ne peut s'auto-référencer, il est impossible de les utiliser pour des variables à incrémentation, telles que gold, nbBought, ...



2.3°/ fonctions d'observation
  • Les propriétés calculées servent à mettre à jour la valeur d'une propriété en fonction d'autres.
  • Il est possible de faire l'inverse : mettre à jour plusieurs propriétés dès qu'une en particulier change.
  • Pour cela, on attache une fonction d'observation à une variable présente dans data. Cette fonction porte le même nom que la variable et doit être définie dans l'attribut watch de l'instance de vue.
  • Elle prend en paramètre la nouvelle et l'ancienne valeur de la variable.
  • A noter qu'il est parfaitement possible d'obtenir le même effet avec plusieurs propriétés calculées à partir de la valeur observée (cf. section précédente avec selectedItem et itemName qui dépendent uniquement de numSel). Mais comme cela peut impliquer pas mal de copier/coller de code, la fonction d'observation est plus concise.

Démonstration :
  • créer un fichier index-04.js et copier/coller dedans :
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
var app = new Vue({
  el: '#mydiv',
  data: {
    items,
    selNums : "",
    selItems : [],
    selNames : ""
  },
  methods: {
    remove : function() {
      this.selItems.forEach(e=> { let idx=items.indexOf(e); items.splice(idx,1); });
      this.selNums="";
    }
  },
  watch:{
    selNums : function(newVal, oldVal) {
      let lst = newVal.split(",");
      this.selNames = "";
      this.selItems = [];
      lst.forEach(e => {if ((items[e-1] != undefined) && (this.selItems.indexOf(items[e-1]) == -1)) {
        this.selNames += items[e-1].name+" ";
        this.selItems.push(items[e-1]);
      }});
    }
  }
})
  • créer un fichier exe-04.html et copier/coller dedans :
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<html>
<head>
  <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
  <script src="model.js"></script>
</head>
<body>
  <div id="mydiv">
    <ol>
      <li v-for="it in items">{{it.name}} : {{it.price}}</li>
    </ol>
    <label for="select">#items :</label><input id="select" v-model="selNums">
    <button v-if="selItems.length>0" @click="remove">remove {{selNames}}</button>
  </div>
  <script src="index-04.js"></script>
</body>
</html>
  • taper dans le champ de saisie une suite d'indices spéarés par des virgules, par ex. 1,3,5. Le contenu du bouton change.
  • cliquer sur le bouton. Les éléments de la liste sont supprimés.
 

Remarques :
  • Dans cet exemple, on utilise pas l'ancienne valeur de selNums.
  • Comme dit plus haut, il serait également possible de mettre selItems et selNames en propriétés calculées. Mais on voit bien que cela nécessite de créer 2 fonctions avec quasi le même code, c.a.d. en gros celui de selNums().