Tutoriel pour apprendre à utiliser le framework Vue.js version 2

Les bases


précédentsommairesuivant

II. Action !

Je vous ai dit dans le précédent chapitre que Vue.js est destiné à créer des interfaces interactives. Pour le moment je ne vous l'ai pas encore prouvé ! Dans ce chapitre on va voir comment gérer les actions de l'utilisateur.

II-A. La directive v-on

Pour intercepter les événements survenant au niveau de la vue, Vue.js offre la directive v-on.

Prenons un petit exemple pour introduire cette notion :

 
Sélectionnez
<div id="tuto">
  <a v-on:click="action">Cliquez ici !</a>
</div>

On a mis la directive v-on dans la balise a. Notez la syntaxe : on fait suivre le nom de la directive de deux points, du nom de l'événement, puis du nom d'une fonction. On comprend vite qu'on va appeler la fonction lorsqu'on clique sur le lien.

Voici le code JavaScript :

 
Sélectionnez
1.
2.
3.
4.
5.
6.
7.
8.
new Vue({
  el: '#tuto',
  methods: {
    action: function () {
      alert('On a cliqué !');
    }
  }
});

Nous découvrons une propriété pas encore rencontrée : methods. C'est ici qu'on va placer les méthodes de la VueModèle. Ici on a besoin d'une méthode action pour répondre à l'événement de clic.

Le résultat au clic est donc l'ouverture de la petite fenêtre d'information :

Image non disponible

Voici une illustration de la liaison :

Image non disponible

On commence à avoir de l'interactivité !

Il existe une syntaxe plus courte et bien pratique pour la directive v-on, il suffit de la remplacer par le caractère @, on écrira ainsi @click.

On peut aussi, au lieu d'une fonction, utiliser une expression comme argument de la directive v-on. Voici un exemple :

 
Sélectionnez
1.
2.
3.
4.
5.
<div id="tuto">
  <h1> 
    <button class="button btn-primary" v-on:click="++n">+</button> {{ n }}
  </h1>
</div>

Cette fois on utilise un bouton et le même événement click. Mais au lieu d'une fonction on se contente d'incrémenter la variable n. D'autre part on affiche la valeur de cette variable avec mustache. Cette approche est à réserver à des traitements sommaires.

Voici le JavaScript :

 
Sélectionnez
1.
2.
3.
4.
new Vue({
  el: '#tuto',
  data: { n: 0 }
});

On initialise n avec la valeur 0 et on sait que sa valeur sera systématiquement répercutée dans la vue. Donc chaque fois qu'on clique sur le bouton la valeur affichée s'incrémente. Voilà l'aspect obtenu :

Image non disponible

Voici une schématisation du fonctionnement :

Image non disponible

II-B. La directive v-bind

Tous les événements disponibles avec JavaScript le sont évidemment aussi avec Vue.js, ce qui ouvre pas mal de perspectives au niveau de l'interactivité. Prenons un petit exemple pour un changement d'aspect au survol. Voici la vue :

 
Sélectionnez
1.
2.
3.
4.
5.
<div id="tuto">
  <h1> 
    <span class="label" v-bind:class="type" v-on:mouseover="changeType">{{type}}</span>
  </h1>
</div>

On voit ici une nouvelle directive : v-bind. Elle permet de lier un attribut à une expression (mustache ne fonctionne pas pour les attributs avec la version 2). Ici on va donc pouvoir changer de façon dynamique  la valeur d'un attribut, ici une classe (ça serait la même chose pour du style).

D'autre part, cette fois l'événement utilisé est mouseover, autrement dit le déclenchement va avoir lieu au survol de l'élément par le curseur de la souris.

Pour avoir le visuel cet exemple nécessite Bootstrap. Donc prévoyez son chargement :

 
Sélectionnez
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css">

Voici le JavaScript :

 
Sélectionnez
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
new Vue({
    el: '#tuto',
    data: {
        type: 'label-primary'
    },
    methods: {
        changeType: function() {
            this.type = (this.type == 'label-primary') ? 'label-success' : 'label-primary';
        }
    }
});

On a dans les données la propriété type qui au départ a la valeur « label-primary ». À chaque survol de l'étiquette par le curseur de la souris cette valeur va changer, alternant entre « label-primary » et « label-success ». Du coup l'aspect à l'écran va aussi changer en conséquence.

D'autre part, on modifie aussi le texte de l'étiquette qui est relié à la même propriété.

Donc au départ on a :

Image non disponible

Et ensuite :

Image non disponible

Et ainsi de suite à chaque survol…

Voici une illustration du fonctionnement :

Image non disponible

Il existe une syntaxe plus courte pour la directive v-bind, il suffit de la remplacer par le caractère « : », on écrira par exemple « :class ».

II-C. Les modificateurs

II-C-1. Les événements

Quand on utilise des événements avec JavaScript on a fréquemment besoin d'utiliser aussi event.preventDefault() ou event.stopPropagation(). On peut évidemment ajouter ces méthodes dans le code mais il y a bien plus simple avec Vue.js !

On peut ajouter aux événements des modificateurs, il en existe quatre :

  • .stop : on stoppe la propagation de l'événement après le nœud actuel du DOM ;
  • .prevent : on empêche l'action implicite de l'événement ;
  • .capture : on utilise le mode capture quand on ajoute l'événement ;
  • .self : la cible doit être l'élément lui-même.

Au niveau de la syntaxe c'est tout simple, par exemple :

 
Sélectionnez
<form @submit.prevent="onSubmit"></form>

En plus on peut chaîner les modificateurs :

 
Sélectionnez
<form @submit.stop.prevent="onSubmit"></form>

II-C-2. Les touches du clavier

Quand on écoute les touches du clavier on aime savoir quelle touche a été activée. Là aussi Vue.js nous simplifie la vie. Il suffit d'ajouter le code de la touche à l'événement :

 
Sélectionnez
<input @keydown.13="submit">

Pour nous simplifier encore plus la vie, on dispose d'alias pour les touches les plus courantes :

  • enter ;
  • tab ;
  • delete ;
  • esc ;
  • space ;
  • up ;
  • down ;
  • left ;
  • right.

Par exemple :

 
Sélectionnez
<input @keydown.enter="submit">

II-D. Le chronomètre

On va poursuivre l'exemple du chronomètre vu précédemment en lui ajoutant de l'interactivité. On va en profiter au passage pour découvrir la directive v-show très utile, qui permet de masquer des éléments du DOM à l'affichage. Voici la nouvelle version complète :

 
Sélectionnez
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.
45.
46.
47.
48.
49.
50.
51.
52.
53.
54.
55.
56.
57.
58.
59.
60.
61.
62.
63.
64.
65.
66.
67.
68.
69.
70.
71.
72.
73.
74.
75.
76.
77.
78.
79.
80.
81.
82.
83.
84.
85.
86.
87.
88.
89.
90.
91.
92.
93.
94.
95.
96.
97.
98.
99.
<!DOCTYPE html>
<html lang="fr">

  <head>
    <meta charset="utf-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <title>Test vue.js</title>
    <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css">
  </head>

  <body>

    <div class="container">

      <div id="tuto" class="text-center">
        <h1>Le chronomètre</h1>
        <hr>
        <h1>
          <span class="label label-primary">{{ time.minutes }}</span> minutes
          <span class="label label-primary">{{ time.secondes }}</span> secondes
        </h1>
        <br>
        <p>
          <button class="btn btn-danger btn-lg" v-show="etat.backward" @click="backward">Effacer</button>
          <button class="btn btn-danger btn-lg" v-show="etat.stop" @click="stop">Arrêter</button>
          <button class="btn btn-primary btn-lg" v-show="etat.play" @click="play">{{ btnPlay }}</button>
        </p>
      </div>

    </div>

    <script src="https://unpkg.com/vue@2.0.3/dist/vue.js"></script>

    <script>

      var vm = new Vue({
        el: '#tuto',
        data: {
          time: {
            minutes: 0,
            secondes: 0
          },
          btnPlay: 'Démarrer',
          etat: {
            stop: false,
            backward: false,
            play: true
          }
        },
        methods: {
          backward: function() {
            chronoReset();
          },
          play: function() {
            chronoStart();            
          },
          stop: function() {
            chronoStop();
          }
        }
      });

      var totalSecondes = 0;
      var timer;

      chronoStart = function() {
        timer = setInterval(function() {
          vm.time.minutes = Math.floor(++totalSecondes / 60);
          vm.time.secondes = totalSecondes - vm.time.minutes * 60;
        }, 1000);
        setEtat(false, true, false);
        vm.btnPlay = 'Continuer';
      };

      chronoStop = function() {
        clearInterval(timer);
        setEtat(true, false, true);
      };

      chronoReset = function() {
        totalSecondes = 0;
        vm.time.minutes = 0;
        vm.time.secondes = 0;
        setEtat(true, false, false);
        vm.btnPlay = 'Démarrer';        
      }

      setEtat = function(play, stop, backward) {
        vm.etat.play = play;
        vm.etat.stop = stop;
        vm.etat.backward = backward;        
      };

    </script>

  </body>

</html>

II-D-1. La Vue

Voici la partie HTML :

 
Sélectionnez
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
<div id="tuto" class="text-center">
  <h1>Le chronomètre</h1>
  <hr>
  <h1>
    <span class="label label-primary">{{ time.minutes }}</span> minutes
    <span class="label label-primary">{{ time.secondes }}</span> secondes
  </h1>
  <br>
  <p>
    <button class="btn btn-danger btn-lg" v-show="etat.backward" @click="backward">Effacer</button>
    <button class="btn btn-danger btn-lg" v-show="etat.stop" @click="stop">Arrêter</button>
    <button class="btn btn-primary btn-lg" v-show="etat.play" @click="play">{{ btnPlay }}</button>
  </p>
</div>

Pour simplifier je n'ai gardé que les minutes et secondes, ce qui est réaliste pour un chronomètre. On utilise deux étiquettes avec une liaison « mustache ». On trouve également trois boutons de commande avec pour chacun :

  1. Une directive v-on (avec la syntaxe courte @) pour détecter l'événement click ;
  2. Une directive v-show pour pouvoir changer la visibilité du bouton.

D'autre part, le troisième bouton a son texte avec une liaison « mustache », il pourra donc changer de nom.

La directive v-show fonctionne avec une valeur booléenne. Si celle-ci est vraie l'élément est affiché, sinon il est masqué (concrètement on a une propriété CSS display qui change de valeur, mais l'élément existe dans le DOM). On va s'en servir ici pour faire apparaître ou disparaître les boutons selon l'étape de fonctionnement du chronomètre.

Il existe aussi la directive v-if qui fonctionne visuellement comme v-show, mais il y a deux différences :

  • avec v-if l'élément n'existe pas dans le DOM ;
  • on peut utiliser la directive v-else pour organiser les conditions.

II-D-2. Le JavaScript

Voyons la partie JavaScript. D'abord la déclaration propre à Vue.js :

 
Sélectionnez
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 vm = new Vue({
  el: '#tuto',
  data: {
    time: {
      minutes: 0,
      secondes: 0
    },
    btnPlay: 'Démarrer',
    etat: {
      stop: false,
      backward: false,
      play: true
    }
  },
  methods: {
    backward: function() {
      chronoReset();
    },
    play: function() {
      chronoStart();            
    },
    stop: function() {
      chronoStop();
    }
  }
});

On trouve :

  • la liaison avec l'élément du DOM : #tuto ;
  • le modèle (data) avec trois propriétés :

    1. time : deux propriétés pour les minutes et secondes du chronomètre,
    2. btnPlay : pour le texte du bouton (Démarrer/Continuer),
    3. etat : trois propriétés pour la visibilité des trois boutons ;
  • les méthodes :

    1. backward : pour remettre le chronomètre à 0,
    2. play : pour lancer ou relancer le chronomètre,
    3. stop : pour arrêter le chronomètre.

On a ensuite les variables globales et les fonctions de gestion :

 
Sélectionnez
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.
var totalSecondes = 0;
var timer;

chronoStart = function() {
  timer = setInterval(function() {
    vm.time.minutes = Math.floor(++totalSecondes / 60);
    vm.time.secondes = totalSecondes - vm.time.minutes * 60;
  }, 1000);
  setEtat(false, true, false);
  vm.btnPlay = 'Continuer';
};

chronoStop = function() {
  clearInterval(timer);
  setEtat(true, false, true);
};

chronoReset = function() {
  totalSecondes = 0;
  vm.time.minutes = 0;
  vm.time.secondes = 0;
  setEtat(true, false, false);
  vm.btnPlay = 'Démarrer';        
}

setEtat = function(play, stop, backward) {
  vm.etat.play = play;
  vm.etat.stop = stop;
  vm.etat.backward = backward;        
};

II-D-3. Le fonctionnement

Au départ on a cet aspect :

Image non disponible

Lorsqu'on clique sur le bouton « Démarrer », le chronomètre se met en marche. Au niveau des boutons, « Démarrer » disparaît et « Arrêter » apparaît :

Image non disponible

Lorsqu'on clique sur « Arrêter » le comptage s'interrompt, le bouton « Arrêter » disparaît. Les boutons « Effacer » et « Continuer » apparaissent :

Image non disponible

Si on clique sur « Effacer » on revient à la situation de départ, et si on clique sur « Continuer » le comptage reprend et le bouton « Arrêter » réapparaît.

II-E. En résumé

  • On gère les événements avec la directive v-on. La syntaxe courte est « @ ».
  • On peut ajouter des modificateurs aux événements.
  • On modifie des attributs avec la directive v-bind. La syntaxe courte est « : ».
  • On masque les éléments du DOM avec la directive v-show.

précédentsommairesuivant

Vous avez aimé ce tutoriel ? Alors partagez-le en cliquant sur les boutons suivants : Viadeo Twitter Facebook Share on Google+   

  

Copyright © 2017 Laravel. Aucune reproduction, même partielle, ne peut être faite de ce site et de l'ensemble de son contenu : textes, documents, images, etc. sans l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu'à trois ans de prison et jusqu'à 300 000 € de dommages et intérêts.