Aperçu des sections

  • Présentation

    Background technique

    Afin de découvrir et utiliser correctement VueJS, il faut être à l'aise avec ces différents concepts :

    • maîtriser un minimum le vanillaJS
    • bien comprendre la logique objet
    • connaître les problématiques front-end (DOM, événements, API, etc...)


    Si vous ne vous sentez pas à l'aise avec ces notions, vous pouvez vous revoir les différents cours traitant ces sujets et vous entraînez sur les exercices appropriés.


    Historique et présentation



    VueJS est un framework JavaScript front-end. Il permet de faciliter la création d'interfaces en offrant une série d'outils adaptés, utiles aux développeurs. La première version de VueJS date de février 2014. La dernière version stable est la 2.6, sortie en février 2019, c'est avec celle-ci que nous allons travailler. Ce framework est open-source, est il est développé en grosse partie par Evan You, ancien développeur d'Angular chez Google, et de Météor, d'autres framework front-end.


    Voici un lien vers le reste de l'équipe : https://fr.vuejs.org/v2/guide/team.html. Il y a pas mal de Frenchies dans l'histoire, ce qui est plutôt une bonne chose car l'équipe aura tendance a "vendre" le framework aux entreprises françaises, ce qui se répercute généralement sur le marché du travail et les offres d'emplois (un peu comme avec Symfony).

    Vue JS fait partie des "big three", les trois frameworks front-end les plus utilisés dans le monde (VueJS, Angular et React). Même s’il est relativement moins utilisés que ses deux concurrents, il bénéficie d'avantages non négligeables, et d'une évolution très positive au fil des années.


    Avantages

    Comparé aux autres frameworks, VueJS est plutôt simple à prendre en main, et vous permettra de vous familiariser avec les différents concepts habituellement implémentés dans les autres frameworks front-end. Il vous sera donc plus facile d'apprendre React ou Angular (ou tout autre framework) par la suite.

    Un autre avantage de Vue, c'est qu'il dispose d'une bonne documentation, à jour, et avec une très grosse partie traduite en Français. Donc pour ceux qui ne sont pas encore trop à l'aise avec la langue de Shakespeare, c'est un point important qui vous enlèvera une difficulté supplémentaire. L'aspect documentation est un critère très important lorsque l'on choisit d'apprendre un nouvel outils, au même titre que la communauté d'utilisateurs.

    Aussi, de part sa légèreté, VueJS est plus rapide est plus performant que d'autres framework plus "lourd". Alors certes, les autres framework proposent plus de choses, ou permettent plus de scalabilité, mais la performance reste tout de même un point non négligeable.


    Benchmark framework JS
    Performances Poids du framework

    Source : https://www.freecodecamp.org/news/a-realworld-comparison-of-front-end-frameworks-with-benchmarks-2019-update-4be0d3c78075/



    Donc avant de passer aux choses sérieuses, commencez par ouvrir la documentation officielle : https://fr.vuejs.org/v2/guide/index.html

    • Installation

      Il y a plusieurs façons d'installer VueJS, mais pour commencer, nous allons utiliser la version standard de développement. Il vous suffit juste d'appeler le fichier de VueJS avec la bonne version via les CDN proposés dans la doc.

      Cette version de développement à l'avantage d'être plus verbeuse au niveau de l'affichage des erreurs, ce qui vous permettra de comprendre plus facilement d'ou viennent vos bugs ou erreurs, et d'avancer pas à pas.
      <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>

      L'appel de ce fichier va télécharger l'ensemble de Vue dans le navigateur client, vous pourrez alors commencer directement à coder votre application.

      • Instance de vue

        Afin de commencer à écrire le code spécifique à notre application, Vue nous impose la création d'un objet de la classe Vue. La classe Vue est déterminée dans le cœur du framework, et votre application est un simple objet de cette classe générique. C'est pour cela que l'on parle d'instance de vue.

        Votre instance de Vue va décrire tout ce dont vous avez besoin pour réaliser votre application : des données, des méthodes, etc... Étant donnée que tout votre application est encapsulée dans un objet "vue", vous bénéficierez d'emblée d'une logique performante pour découper les différentes facettes de votre code. C'est tout l’intérêt des frameworks.

        Commençons par découvrir deux propriétés basiques d'une instance de Vue :

        • le sélecteur d'élément, qui permet de définir quelle partie de votre page doit être gérée par Vue
        • les data, qui vont contenir les données nécessaires au bon fonctionnement de votre application


        Voici comment ça se présente :

        let vm = new Vue({    /*Création d'une instance de vue, et passage du code en option*/
          el: '#app', /*Sélecteur. Même syntaxe que le CSS*/
          data: { /*Données de l'application*/
            pseudo: 'Yolo31',
          age: '22'
          }
        });


        Il y a certaines choses à retenir dans cet exemple simple :

        • on crée un objet, et on lui envoie notre code directement en paramètres d'options (avec les accolades)
        • certains mots clés sont imposés par le framework (el pour élément, data pour données, et il y en a de nombreux autres)
        • le typage des paramètres est imposé aussi (el = string, data = objet). Bien souvent, ce seront des objets que vous passerez, mais attention à certaines exceptions : se référer à la doc.


        A noter : j'ai choisi un exemple simple avec des données qui contiennent uniquement des chaînes de caractères, mais on peut leur assigner tout type de valeurs (tableaux, entiers, objet, etc...).


        Afficher des données

        Maintenant que nos données sont décrites dans notre objet de vue, nous souhaitons les afficher dans notre page HTML. Pour ce faire, on utilisera la syntaxe "moustaches" (on parle aussi d'interpolation de chaîne) :

        <div id="app">
        <p>Bienvenue dans votre espace perso {{pseudo}}. Vous avez {{age}} ans.</p>
        </div>

        Affichera :

        Bienvenue dans votre espace perso Yolo31. Vous avez 22 ans.


        Cette approche est très forte, car si Vue est capable d'écrire des données JavaScript dans votre page web via un système de template, il est surtout capable de mettre à jour ces données dès qu'elles changent. C'est ce qu'on appelle la réactivité. Le DOM réagi aux changements de données du modèle JS grâce aux mécanismes internes du framework. Et c'est très utile lorsque l'on travaille avec une API qui ne renvoi que des jeux de données en JSON (contrairement à une requête HTTP classique qui renvoi l'ensemble du document HTML).



        => Nous approfondirons les différentes possibilités d'une instance de vue au fur et à mesure.

        • Vue dev tool

          Il existe un plugin pour navigateur qui permet de travailler plus efficacement avec VueJS. Le DevTools de Vue est optimisé, et va vous permettre de gagner du temps dans votre développement. Il permet l'affichage "user-friendly" de vos données, instances, composants, événements, etc... Ce qui vous permet de visualiser le comportement de votre appli sans faire trop de console.log et offre un certains confort durant les phases de développement.

          Voici un screenshot d'exemple :

          • Cycle de vie de l'application

            Une instance de vue suit ce que l'on appelle un cycle de vie. C’est-à-dire que le framework va passer par différentes étapes lors de l'exécution de votre script, et chaque étape pourra être détectée via des sortes d’événements propres à Vue. Cela peux s'avérer pratique pour exécuter selon différentes étapes du cycle d'exécution de votre application.

            Ce cycle de vie est visualisable à l'aide de ce diagramme :


            Les hooks (crochets) du cycle de vie sont des méthodes réservés à la racine de l'instance de vue, et elles peuvent s'écrire de cette manière :

            let vm = new Vue({
              el: '#app',
              data: {
                nom: 'Buabent',
                prenom: 'Julien'
              },
              updated: function() { /*Appel le hook "updated"*/
                console.log('données modifiées !'); /*Code a exécuter lors du passage dans cet événement*/
              }
            });

            • Données calculées

              Les computed data (ou données calculées), sont des représentations abstraites de données "réelles" (cqfd: celles qui sont contenu dans data). Dans notre exemple, nous avons deux propriétés distinctes : le nom et le prénom. Bien souvent, on va avoir besoin d'afficher les deux à la fois, via une variable que l'on pourrait nommer nomComplet. De plus, cette propriété nomComplet doit retourner un nom formaté selon certains critères. 

              Par exemple :

              • en premier, le prénom avec la première lettre en majuscule
              • en second, le nom de famille en majuscule

              Exemple : Pierre DURAND


              VueJS propose donc ce mécanisme. La propriété nomComplet, n'est pas une propriété de l'objet en tant que tel, mais une propriété abstraite, composée d'autres propriétés. 

              Voici les avantages de ce mécanisme :

              • vous n'aurez pas besoin de gérer plusieurs variables qui font "presque" le même job (nom, prénom, nomComplet)
              • quand les data se mettent à jour, les computed data suivent automatiquement
              • les computed data sont mise en cache dans vueJS, donc leur accès est très optimisé (elles ne sont pas recalculées à chaque appel)


              Les computed data se placent dans la propriété computed de l'instance de vue :

              let vm = new Vue({
                el: '#app',
                data: {
                  fiesta: 'noël',
                  year: 2019
                },
                computed: {
                  afficheMessage: function() {

                    return `Je vous souhaite de bonnes fêtes de ${this.fiesta} ${this.year}`; /*Appel des propriétés de l'instance dans la fonction*/
                  }
                }

              });


              Pour afficher votre computed data dans votre template, vous pouvez utiliser la même syntaxe qu'une propriété normale, à savoir la syntaxe moustache.

              <p>Notre entreprise se fait un plaisir de blablabla....blablabla....</p>
              <p class="voeux">{{afficheMessage}}</p>


              Note : on peux définir un setter manuellement dans une propriété calculée afin de mettre une certaine logique lors de sa modification => https://fr.vuejs.org/v2/guide/computed.html#Mutateur-calcule
              • Filtres

                Les filtres sont une autre fonctionnalité basique de Vue. Au même titre que les autres propriétés standards, vous allez pouvoir définir une série de filtres utiles à votre application dans les options de votre instance. Ces filtres vont vous permettre d'appeler une fonction lors de l'affichage d'une des propriétés dans votre DOM. Le contenu de la propriété (par exemple un texte), va automatiquement être transmis comme premier paramètre de votre filtre, qui va appliquer un traitement dans le but de vous renvoyer la propriété après traitement par le filtre.

                Voici un exemple de mise en place d'un filtre qui va mettre la première lettre d'une chaîne de caractères en majuscule :

                filters: {     //Emplacement des filtres dans l'objet Vue
                  capitalize: function(value) { //Création d'un filtre et récupération du premier paramètre
                    return value.charAt(0).toUpperCase() + value.slice(1); //Code et retour de la valeur
                  }
                }


                Une fois votre filtre opérationnel, vous pourrez l'appliquer à l'affichage de vos propriété dans votre template :

                <p>Mon nom de famille est {{nom | capitalize}}</p>


                Si nom est "durand", ce code affichera :

                Mon nom de famille est Durand


                Note : on peut envoyer plus de paramètres à un filtre, et affiner les différentes possibilités. Je vous renvoie à la documentation sur les filtres pour toutes ces subtilités.
                • Evénements natifs

                  Comme tous les autres concepts récurrents du développement web front-end, VueJS propose une gestion facilité des événements. Il y a différentes manières de gérer les événements avec Vue, et on peut modifier de nombreux comportements assez facilement via la syntaxe de Vue. Pour commencer, nous allons aborder les événements de manière assez simple.

                  Pour écouter un événement sur un élément du DOM, il suffit d'utiliser la syntaxe suivante dans votre page HTML :

                  <button v-on:click="doSomething">Test</button>

                  • le v-on dit à Vue que l'on souhaite écouter un événement sur la balise. (comme la syntaxe native onClick="")
                  • le click permet de déterminer quel événement on souhaite écouter (click, keyup, etc...)
                  • et le doSomethings représente une instruction valide JS (qui peux être une instruction basique, ou bien l'appel à une méthode de l'instance de Vue)


                  L'écriture raccourcie pour les événements dans Vue et l'utilisation du caractère @.

                  Exemple :

                  <button @click="doSomething">Test</button>
                  Voir la doc pour toutes les autres possibilités concernant les événements : https://fr.vuejs.org/v2/guide/events.html

                  • Rendu conditionnel et de liste

                    Avec Vue, vous pouvez déterminer l'affichage d'un élément, ou boucler sur un ensemble de valeurs en utilisant les directives v-if ou v-for. Comme d'habitude, il y a de nombreuses manières de procéder, mais nous verrons seulement les plus simples dans un premier temps.


                    Rendu conditionnel

                    Si vous souhaitez conditionner l'affichage d'une partie de votre DOM à la valeur d'une propriété de votre instance, voici comment procéder :

                    <p v-if="afficheMonTexte == true">Ce texte ne sera affiché que lorsque la propriété afficheMonTexte aura la valeur true</p>

                    Cette syntaxe va régénérer le DOM quand la valeur de afficheMonTexte changera.


                    On peut aussi utiliser l'expression v-else, qui fonctionne de la même manière qu'un if/else classique.

                    <p v-if="afficheMonTexte == true">Ce texte ne sera affiché que lorsque la propriété afficheMonTexte aura la valeur true</p>

                    <p v-else>Ce texte s'affichera seulement si affichemonTexte est à false</p>
                    D'autres subtilités sont possibles avec les rendus conditionnels, mais cela reste assez simple. Il existe la directive v-show, qui donne à peu près le même résultat, mais qui va simplement cacher une balise via la propriété CSS display. Tandis qu’un v-if va vraiment régénérer le DOM.


                    Rendu de liste

                    VueJS propose aussi une syntaxe de template pour les boucles. Si vous devez générer X éléments dans votre DOM, et que ces éléments sont contenus dans un tableau (ou un itérable), alors vous pourrez utiliser la directive v-for. Voici un exemple :

                    JS :

                    let vm = new Vue({
                      el: '#app',
                      data: {  
                        notes: [15, 8, 12, 18, 11, 5]
                      }
                    });


                    HTML :

                    <ul>
                    <li v-for="note of notes">{{note}} / 20</li>
                    </ul>

                    Ce code va produire une liste HTML, contenant une note par point de liste :


                    On utilise la syntaxe moustache pour afficher les données en texte brut dans la boucle. Dans cet exemple, nous sommes très proches de l'écriture JS for(item of items){...}, donc c'est assez simple à prendre en main si on connait déjà bien JavaScript.

                    Attention : faites attention à l'emplacement du v-for. Dans cet exemple on pourrait avoir tendance à le placer sur la balise <ul>, mais c'est bien sur l'élément que l'on souhaite répéter qu'il faut placer la directive, et non sur son parent.
                    Allez jeter un œil sur la documentation sur le rendu de liste pour voir toutes les nuances de boucles possibles.


                    (Gérer les attributs HTML ?)

                    • Liaison de données uni-directionnelle

                      Un des avantages majeurs de vueJS, et des frameworks JS en général, c'est le binding (liaison) automatique en les propriétés de votre objet JS, et leur affichage dans le DOM. Ce mécanisme est très pratique, car cela vous évite d'avoir à écrire les lignes de codes qui vont devoir modifier le DOM quand les valeurs changent. L'accès au DOM en vanillaJS est très verbeux, et ça n'est pas ce qu'il y a de plus passionnant à coder...

                      Le one-way data binding, c'est une façon de dire que les données ne changent que dans un seul sens : du JS vers le DOM. Donc quand la valeur d'une propriété va changer dans le modèle (vue modèle), Vue va automatiquement mettre à jour le DOM.


                      Lier des données sur un attribut de balise HTML
                      Les propriétés data sont automatiquement bindées dans le DOM lorsque l'on affiche du texte brut dans le HTML grâce à la syntaxe moustache. En revanche il faudra utiliser la syntaxe v-bind:nomDeLAttribut lorsque l'on voudra binder un attribut à l'intérieur d'une balise HTML.

                      Exemple : 

                      <a v-bind:href="dataUrl">un lien </a>

                      Dans cet exemple, la directive v-bind permet la liaison avec l'attribut href de la balise a

                      Note : vous n'avez pas besoin d'utiliser les moustaches dans la liaison par attribut. Vous écrivez directement le nom de la donnée.
                      • Liaison de données bi-directionnelle

                        VueJs propose aussi un mécanisme qui permet de binder des propriétés dans les deux sens (DOM <=> JS). C'est ce que l'on appel le two-way data binding (liaison bi-directionnelles des données). Cela est très pratique lorsque l'on utilise des éléments de formulaire par exemple.

                        Pour faire du two-way data binding, il suffit d'utiliser la directive v-model de Vue dans vos balises de formulaire, et de lui dire avec quel propriété du modèle vous souhaitez binder la valeur de votre balise.

                        Exemple : 

                        <input type="email" v-model="userEmail" />

                        Cet exemple permettra de modifier la valeur d'une propriété userEmail présente dans le modèle. Et si la valeur de la propriété email change dans le modèle, elle sera automatiquement mis à jour dans le DOM.

                        Attention : dans certains cas de figure, il vous faudra passer par la directive v-bind:value pour respecter le typage JS des valeurs qui sont envoyer vers Vue ('true' (string) est différent de true (bool) par exemple). Le DOM ne traite que des chaines de caractères, donc il vous faudra passer par v-bind pour respecter le typage si vous traitez autre chose que des chaînes de caractères.

                        Exemple : 

                        <input type="radio" v-model="areYouWebDev" v-bind:value="true" /> Oui
                        <input type="radio" v-model="areYouWebDev" v-bind:value="false" /> Non

                        Dans cet exemple, si on avait mis simplement value="true", on aurait alors envoyé une chaîne de caractère à un booléen, ce qui peut très vite générer des bugs.


                        Modificateurs

                        Ces options vous permettent de modifier un comportement par défaut du navigateur en demanant à vue d'opérer une modification pré-établie sur la données avant de la mettre en jour dans le DOM. Si vous souhaitez par exemple appliquer une fonction trim sur une chaîne de caractère (enlève tous les espaces avant et après), alors vous pourrez écrire quelque chose comme ceci :

                        <input type="email" v-model.trim="userEmail" />   //Nettoiera automatiquement les espaces saisis avant et après l'email de l'utilisateur


                        Documentation officielle : https://fr.vuejs.org/v2/guide/forms.html

                        • Méthodes personnalisées

                          Au même titre qu'un objet classique, vous pouvez créer vos propres méthodes dans une instance de Vue. 


                          Il vous suffit de rajouter la propriété "methods" à l'instance de Vue, puis de définir des méthodes de cette manière :

                          methods: {
                            somme: function() {
                              let a = parseInt(prompt('Premier nombre ?'));
                              let b = parseInt(prompt('Deuxième nombre ?'));
                              alert(a + b);
                            }
                          }


                          Vous avez accès aux propriétés de l'objet en cours via l'utilisation du mot clé this, comme dans de la POO normale :

                          methods: {  
                            afficheStory: function() {
                              console.log(this.story); //Exemple avec les exercices du cours
                            }
                          }

                          Pour conclure, vous pouvez évidement passer des paramètres à vos méthodes, et les appeler entre elles :

                          methods: {
                            somme: function(a, b) {;
                              alert(a + b);
                            },
                            afficheStory: function() {
                              console.log(this.story);
                            },
                            megaMethod: function(a, b) {
                              this.somme(a, b);
                              this.afficheStory();
                            }
                          }

                          Pour appeler une méthode, vous pouvez - par exemple - passer par un événement click de votre DOM :

                          <button v-on:click="megaMethod(8,6)">Mega Method</button>    

                          Cet exemple appellera la méthode megaMethod avec les paramètres 8 et 6 ce qui aura pour effet d'afficher la somme de 8 + 6, puis d'afficher la propriété story de l'objet en cours.

                          Attention : il ne faut pas utiliser les fonctions fléchées dans les méthodes qui travaillent sur l'instance de Vue, car vous perdrez le contexte de l'objet en cours, et vos propriétés et méthodes deviendront difficilement accessibles depuis l'intérieur de la méthode.

                          • Composants

                            Les composants de VueJS vous permettent de découper votre application en plusieurs morceaux relativement indépendants les uns des autres. Cela permet de bien spécifier chaque partie du code selon les besoins de l'application. Les composants sont toutefois reliés entre eux via un système de lien de parenté, ou chaque composant est enfant ou parent d'un autre, selon son degrés de "généricité". Avec comme composant principal l'instance de Vue (le modèle).


                            Création d'un composant

                            VueJS propose deux type de case différentes pour le nom des composants :

                            • le kebab case (ex: mon-composant)
                            • le PascalCase (ex : MonComposant)


                            Vous pouvez utiliser les deux, mais la syntaxe kebab case est à privilégier dans les appels des composants dans vos templates.


                            Composants global vs local

                            Il y a deux manières de créer un composant : https://fr.vuejs.org/v2/guide/components-registration.html#Creation-globale

                            Voici un exemple de création de composants simples, un en local et l'autre en global :

                            Javascript :


                            Vue.component('global-cmp', {
                                template: '<div>composant global</div>'
                              });

                              let LocalCmp = {
                                template: '<div>composant local</div>',
                              };

                              let vm = new Vue({
                                el: '#app',
                                components: {
                                  'local-cmp': LocalCmp
                                }
                              });


                            Et voici comment les appeler dans le DOM :

                            <div id="app">
                                <global-cmp></global-cmp>
                                <local-cmp></local-cmp>    
                            </div>


                            Intégrez ce code dans votre TD afin de constater le bon fonctionnement. Vous remarquerez que le composant global est accessible directement dans le template de Vue, tandis que le composant local doit être déclaré dans le modèle afin de pouvoir être utilisé.


                            La propriété "template"

                            Comme vu dans l'exemple précédent, la propriété template est la partie du composant qui sera compilée par Vue pour effectuer le rendu et mettre à jour le DOM. Dans les exercices précédents, nous avons codés des exemples qui régénérait directement le HTML contenu dans le composant Root (#app). Désormais, nous allons pouvoir écrire des petits bouts de HTML dans chaque composants, puis insérer directement les composants dans l'application (comme enfant de Root). Vue se chargera de compiler le template pour remplacer le composant par du code HTML. Les composants fonctionnent à peu près de la même manière que le code HTML standard, à savoir que l'on va pouvoir utiliser toutes les fonctionnalités de Vue dans les template (rendu conditionnel, binding, etc...).

                            Exemple :

                            template: `   // <-- back tick pour template string. Obligé si vous ne voulez pas concaténer à tout va...
                                <ul>
                                  <li v-for="user in data">
                                    <user-details v-bind:usr="user" v-on:accept="registerUser(user)"></user-details>
                                  </li>
                                </ul>`


                            Les data

                            Dans les composants Vue, la propriété data (qui représente les données propres à un composant), doit être renseignée sous la forme d'une fonction qui retourne la liste des propriétés du composant (afin de garder les données de toutes les instances d'un composant indépendantes). A part ça, cela fonctionne de la même manière que les data dans le modèle.

                            Exemple :

                            data: function() {
                                  return {
                                    nom: '',
                                    prenom: ''
                                  }
                            }



                            Les props

                            Les props sont des données que l'ont va pouvoir passer d'un composant parent vers un composant enfant. On va déterminer quelles props attends le composant enfant (un peu comme les paramètres d'une fonction), et on va pouvoir lui passer lors de la création, un peu comme on passe des paramètres à une fonction. 

                            L'appel via le DOM se fait comme cela :

                            <component-name min="5" max="15"></component-name>

                            La déclaration dans le composant se fait de cette manière :

                            props: ['min', 'max']  //Ici on prévoit que le composant peut recevoir une prop min et une prop max

                            On pourra alors réutiliser les props reçues dans le composant, que ce soit dans le template (via la syntaxe moustache), ou bien dans le JS (via l'utilisation du mot-clé this).

                            Exemple d'un composant simple :

                            JS :

                            Vue.component('blog-post', {  
                              props: ['postTitle'],
                              template: '<h3>{{ postTitle }}</h3>'
                            })

                            Appel :

                            <blog-post post-title="Hello !"></blog-post>



                            A rajouter :

                            • définition des props sous forme d'objet avec type (multiples) et valeur par défaut
                            • différentes façon d’enregistrer les components
                            • propriété dynamiques dans l'envoi des props (avec le :)
                            • this.$parent (mais attention, dépendance avec le parent)
                            • émission d’événement depuis un composant enfant vers parent avec this.emit('evenementperso'), puis on utilise l'evenement comme les événements standards
                            • les slots