Migration de jQuery vers Vue.js

L'auteur de l'article, dont nous publions la traduction aujourd'hui, estime qu'il existe de nombreux autres programmeurs dans le monde qui, lorsqu'ils ont besoin de développer une application Web simple, se tournent vers jQuery . Habituellement, cela se produit lorsqu'une certaine page doit être équipée de fonctionnalités interactives simples, mais l'utilisation d'une sorte de framework JavaScript semble exagérée. Après tout, ce sont des kilo-octets de code inutile, des modèles, des outils pour construire des projets, des outils pour emballer des modules ... En même temps, se connecter à une page jQuery en utilisant une ressource CDN est aussi simple que de peler des poires.



Cet article explique comment traduire un projet créé à l'aide de jQuery en Vue.js. Ce projet sera créé sur jQuery, puis repensé à l'aide de Vue. L'auteur du matériel veut démontrer à tout le monde que l'utilisation de Vue, même dans des projets relativement petits, ne signifie pas nécessairement une augmentation excessive de la taille du code de tels projets et une charge supplémentaire importante pour le programmeur. Ceci, au contraire, avec presque la même taille de code auxiliaire que lors de l'utilisation de jQuery, vous permet d'augmenter la productivité et d'améliorer la qualité des applications.

Aperçu du projet


Nous allons développer un simple compte électronique basé sur ce modèle open source de Sparksuite.

Souvent, ces études de cas utilisent toutes sortes de listes de tâches. J'espère qu'un départ de cette tradition rendra l'histoire plus fraîche et plus intéressante, et, en même temps, notre tâche sera assez difficile pour démontrer les avantages d'utiliser quelque chose comme Vue pour développer de petits projets. Le manuel est conçu pour que tout le monde sans difficultés particulières puisse le reproduire et maîtriser les méthodes de travail proposées.

Voici le modèle de compte avec lequel nous voulons travailler.


Facture électronique

Nous allons lui ajouter des fonctionnalités interactives, afin qu'il soit possible de choisir un produit, sa quantité et son prix unitaire. Lors de la modification des valeurs, le coût total des marchandises et le montant total du document seront recalculés. De plus, nous ajouterons ici un bouton qui vous permet d'insérer de nouvelles lignes vides dans le compte.

J'ai modifié le modèle en convertissant le code HTML de la chaîne vide au format suivant:

<tr class="item">  <td><input value="" /></td>  <td>$<input type="number" value="0" /></td>  <td><input type="number" value="1" /></td>  <td>$0.00</td> </tr> 

Développement de projet JQuery


Voyons d'abord comment résoudre notre problème à l'aide de jQuery.

 $('table').on('mouseup keyup', 'input[type=number]', calculateTotals); 

Nous connectons l'écouteur d'événements à la table. Cet auditeur appellera la fonction calculateTotals lorsque les valeurs correspondant au coût unitaire du produit ou à sa quantité changent:

 function calculateTotals()  { const subtotals = $('.item').map((idx, val)  => calculateSubtotal(val)).get(); const total = subtotals.reduce((a, v)  => a + Number(v), 0); $('.total td:eq(1)').text(formatAsCurrency(total)); } 

La fonction prend les lignes du tableau et les parcourt, en passant chacune des lignes à la fonction calculateSubtotal et en résumant les résultats. Le résultat du calcul tombe dans la constante constante. Par conséquent, le montant total du document est remplacé dans le champ correspondant du compte.

 function calculateSubtotal(row) { const $row = $(row); const inputs = $row.find('input'); const subtotal = inputs[1].value * inputs[2].value; $row.find('td:last').text(formatAsCurrency(subtotal)); return subtotal; } 

Dans ce code, nous prenons des références à tous les champs <input> présents dans la ligne, puis nous multiplions les valeurs stockées dans les deuxième et troisième champs pour obtenir la valeur de subtotal - subtotal . Cette valeur est ensuite insérée dans la dernière cellule de la ligne. Nous formater cette valeur à l'aide de la fonction formatAsCurrency . Voici son code:

 function formatAsCurrency(amount) { return `$${Number(amount).toFixed(2)}`; } 

De plus, nous avons une petite fonction auxiliaire que nous utilisons afin d'assurer la même apparence des champs avec les montants pour les marchandises et pour le document dans son ensemble. À savoir, nous devons avoir le signe $ devant les nombres dans ces champs, et que ce soient des nombres décimaux avec deux décimales.

 $('.btn-add-row').on('click', () => { const $lastRow = $('.item:last'); const $newRow = $lastRow.clone(); $newRow.find('input').val(''); $newRow.find('td:last').text('$0.00'); $newRow.insertAfter($lastRow); $newRow.find('input:first').focus(); }); 

Et enfin, nous avons un gestionnaire d'événements pour cliquer sur le bouton Add row , qui sert à ajouter une nouvelle ligne au document. Ici, nous prenons la dernière ligne du tableau contenant les données du produit et en faisons une copie. Dans le même temps, nous insérons des données standard dans les champs de cette nouvelle ligne. De plus, nous pouvons prendre soin de la commodité de l'utilisateur et mettre l'accent sur le premier champ d'une nouvelle ligne, ce qui permettra à l'utilisateur, immédiatement après l'ajout d'une nouvelle ligne, de commencer à saisir des données dans son premier champ.

Voici un exemple de travail d'un compte dont les fonctionnalités interactives sont implémentées à l'aide des outils jQuery.

Inconvénients de la solution basée sur jQuery


Demandons-nous quels sont les inconvénients de l'approche ci-dessus, ou plutôt, comment améliorer notre projet.

Vous avez peut-être entendu parler de nouvelles bibliothèques, comme Vue et React, qui leur permettraient de fonctionner dans un style déclaratif plutôt qu'impératif. Si vous regardez le code jQuery ci-dessus, il est clair qu'il est principalement lu comme un ensemble d'instructions décrivant la manipulation du DOM. Le but de chaque section de ce code, c'est-à-dire la réponse à la question de ce qu'il fait, est souvent assez difficile à comprendre en regardant comment il le fait. Bien sûr, vous pouvez clarifier les intentions des fragments de code utilisés en les divisant en fonctions avec des noms soigneusement choisis. Cependant, si vous laissez ce code pendant un certain temps, puis y revenez, il s'avère que pour le comprendre, vous devez encore faire quelques efforts.

Un autre problème avec ce code est que l'état de l'application est stocké dans le DOM. Les informations sur les produits que l'utilisateur souhaite commander n'existent que dans le cadre du balisage HTML dans l'interface utilisateur. Si tout ce dont nous avons besoin est de produire des données en un seul endroit, ce problème ne semble pas si grave. Cependant, dès qu'il devient nécessaire d'afficher ces données à plusieurs endroits de l'application, nous sommes confrontés à la tâche de synchronisation des données. Sans, comme dans notre cas, une source unique de données fiables, il est très difficile de les maintenir à jour tout au long de l'application.

En utilisant jQuery, rien ne nous empêche de stocker l'état de l'application en dehors du DOM et d'éviter le problème décrit ci-dessus, des bibliothèques telles que Vue fournissent des fonctionnalités qui aident à créer des applications avec une bonne architecture. Ces bibliothèques aident le programmeur à écrire du code plus propre et plus structuré.

Traduction de projet sur Vue


Voyons maintenant comment recréer la même fonctionnalité sur Vue. Afin de tirer parti des capacités de Vue, connectez simplement cette bibliothèque à une page Web standard, comme vous le faites avec jQuery. Autrement dit, il n'est pas nécessaire d'utiliser le système pour emballer des modules ou un transpilateur; vous n'avez pas besoin de diviser l'application en composants et de décomposer leur code en fichiers .vue.

Nous commençons à traduire le projet en Vue en remplaçant le contenu de la <script> :

 <script src="https://cdn.jsdelivr.net/npm/vue@2.5.16/dist/vue.js"></script> 

L'étape suivante consiste à créer une nouvelle instance de Vue:

 const app = new Vue({ el: 'table' }); 

Le seul paramètre à passer au constructeur de la nouvelle instance de Vue est el . Il s'agit d'un sélecteur (le même que celui utilisé dans jQuery) qui identifie la partie du document que nous voulons contrôler avec Vue.

Vue peut être affecté à des tâches de différentes tailles - de la gestion d'une page entière (dans le cas, par exemple, d'une application d'une seule page) à un petit fragment enfermé dans une <div> . Dans notre exemple, Vue sera responsable de travailler avec la table HTML.

Les données


Ajoutez des données conditionnelles pour trois lignes du document à l'instance Vue:

 const app = new Vue({ el: 'table', data: {   items: [     { description: 'Website design', quantity: 1, price: 300 },     { description: 'Hosting (3 months)', quantity: 1, price: 75 },     { description: 'Domain name (1 year)', quantity: 1, price: 10 },   ] } }); 

La propriété data est l'endroit où nous stockons l'état de l'application. L'état comprend non seulement les données avec lesquelles notre application doit fonctionner, mais également des informations sur l'état de l'interface utilisateur (par exemple, quelle section de l'application, composée de plusieurs onglets, est actuellement active, ou si un certain widget est minimisé, comme un "accordéon", ou élargi).

Vue permet de garder l'état de l'application distinct de sa présentation (c'est-à-dire du DOM) et aide à stocker l'état de manière centralisée en un seul endroit, qui est une source unique de données fiables.

Modification du modèle


Configurez maintenant le modèle pour qu'il affiche les données stockées dans l'objet de data . Puisque nous avons dit au framework que nous voulions travailler avec la table en utilisant l'instance de Vue, nous pouvons utiliser la syntaxe du modèle Vue dans le code HTML qui décrit cette table afin de dire à Vue comment rendre la table et comment l'utiliser au travail.

En utilisant l'attribut v-for , nous pouvons déduire un bloc de code HTML pour chaque élément du tableau des items :

 <tr class="item" v-for="item in items"> </tr> 

Vue répétera ce balisage pour chaque élément du tableau (ou objet) transmis à v-for . Cela nous permet de faire référence à chaque élément de la boucle. Dans ce cas, cet élément est représenté par la variable item . Étant donné que Vue supervise les propriétés de l'objet de data , le framework met à jour dynamiquement le balisage lorsque le contenu du tableau d' items change. Tout ce que nous devons faire est de modifier l'état en ajoutant ou en supprimant des éléments, et Vue mettra automatiquement à jour l'interface utilisateur.

De plus, nous devons ajouter des champs de saisie que l'utilisateur pourrait remplir en entrant une description du produit, le prix unitaire, la quantité:

 <td><input v-model="item.description" /></td> <td>$<input type="number" v-model="item.price" /></td> <td><input type="number" v-model="item.quantity" /></td> <td>${{ item.price * item.quantity }}</td> 

Ici, nous utilisons l'attribut v-model pour configurer la liaison de données bidirectionnelle entre les champs d'entrée et les propriétés dans le modèle de données. Cela signifie que la modification des données dans les champs de saisie entraînera leur modification dans le modèle, et vice versa.

Dans la dernière cellule, nous utilisons des accolades {{}} , nous les utilisons pour afficher du texte. Vous pouvez utiliser n'importe quelle expression JavaScript fonctionnelle entre parenthèses. Dans ce cas, nous multiplions les deux propriétés de l'élément et produisons ce qui s'est passé. Encore une fois, Vue supervise le modèle de données; la modification d'une propriété recomptera automatiquement l'expression.

Événements et méthodes


Nous avons maintenant un modèle prêt à afficher la collection d' items et nous sommes confrontés à la question de savoir comment ajouter de nouvelles lignes au tableau. Puisque Vue affichera tout ce qui se trouve dans le tableau des items sur la page, afin d'afficher une chaîne vide sur la page, il suffit de passer l'objet Vue avec toutes les valeurs qui devraient être présentes dans le tableau des items .

Afin de créer une fonction accessible à partir du modèle, vous devez passer cette fonction à l'instance Vue en tant que propriété de l'objet methods :

 const app = new Vue({ // ... methods: {   myMethod() {} }, // ... }) 

addRow méthode addRow , qui peut être appelée pour ajouter un nouvel élément au tableau d' items :

 methods: { addRow() {   this.items.push({ description: '', quantity: 1, price: 0 }); }, }, 

Veuillez noter que toutes les méthodes que nous créons seront automatiquement liées à l'instance Vue, ce qui nous permettra d'accéder aux propriétés de l'objet de data et d'autres méthodes en tant que propriétés de this ci à partir de ces méthodes.

Nous avons donc maintenant une méthode. Comment l'appeler en cliquant sur le bouton Add row ? Pour ajouter des écouteurs d'événements aux contrôles dans un modèle, Vue utilise la syntaxe v-on:event-name .

 <button class="btn-add-row" @click="addRow">Add row</button> 

Vue fournit également un raccourci pour la construction v-on : qui ressemble à @ . Il est utilisé dans l'extrait de code ci-dessus. Vous pouvez utiliser n'importe quelle méthode de l'instance Vue comme gestionnaire d'événements.

Propriétés calculées


Il ne nous reste plus qu'à retirer le montant total du document au bas de la facture. Cela peut être fait dans le modèle lui-même. Comme déjà mentionné, Vue vous permet de placer n'importe quelle expression JS fonctionnelle dans les constructions à partir de crochets. Cependant, il est préférable de suivre une approche dans laquelle seule une logique très simple et rien de plus est stockée dans le modèle. Si la logique est séparée du modèle, le code sera plus propre, il sera plus facile à tester.

À cette fin, nous pouvons utiliser la méthode habituelle, mais je pense que dans ce cas, la propriété dite calculée est la meilleure pour nous. Le travail avec de telles propriétés ressemble au travail ci-dessus avec les méthodes. A savoir, pour créer de telles propriétés, un objet computed est passé à l' computed Vue, contenant des fonctions dont nous voulons utiliser les résultats d'exécution dans le modèle:

 const app = new Vue({ // ... computed: {   total() {     return this.items.reduce((acc, item) => acc + (item.price * item.quantity), 0);   } } }); 

Maintenant, la propriété calculée peut être référencée à partir du modèle:

 <tr class="total"> <td colspan="3"></td> <td>Total: ${{ total }}</td> 

Comme vous l'avez peut-être remarqué, les propriétés calculées dans le modèle fonctionnent comme s'il s'agissait de données. Dans ce cas, vous n'avez pas besoin d'appeler quoi que ce soit dans le modèle. L'utilisation de propriétés calculées présente un autre avantage. Vue est un système assez intelligent, il met en cache les valeurs retournées et ne les raconte que si les propriétés dont dépendent les valeurs des propriétés calculées sont modifiées.

Si nous utilisions la méthode pour calculer le montant total du document, les calculs seraient effectués à chaque sortie du modèle. Mais, puisque nous utilisons la propriété calculée, le montant total est recalculé uniquement lors de la modification des valeurs de quantity ou de price dans les lignes du tableau.

Filtres


Vous avez peut-être remarqué qu'il y a une petite erreur dans l'implémentation de notre projet créé à l'aide de Vue. Cela consiste dans le fait que lorsque les prix des marchandises individuelles sont exprimés en nombres entiers, les valeurs calculées des montants totaux en lignes et le montant total dans le document sont affichés en dollars entiers, sans cents. Nous aimerions, comme dans l'exemple jQuery, ces nombres contiennent toujours deux décimales.

Au lieu de modifier le code responsable du calcul de la valeur totale de la ligne et le code qui calcule le montant total du document, nous pouvons tirer parti des fonctionnalités pratiques de formatage des données de Vue. Il s'agit de filtres.

Comme vous l'avez probablement déjà compris, pour créer un filtre, il suffit de passer un objet (des filters dans ce cas) avec la clé correspondante à l'instance Vue:

 const app = new Vue({ // ... filters: {   currency(value) {     return value.toFixed(2);   } } }); 

Ici, nous avons créé un filtre très simple appelé currency . Il appelle la fonction toFixed(2) pour la valeur numérique qui lui est transmise et renvoie le résultat. Vous pouvez utiliser ce filtre dans le modèle comme suit:

 <td>Total: ${{ total | currency }}</td> 

Voici l' implémentation terminée de notre projet sur Vue.

Résumé


Si vous comparez deux versions du projet, l'une créée à l'aide de jQuery et la seconde écrite dans Vue, vous remarquerez les points forts suivants de l'application basée sur Vue:

  • Une séparation claire entre l'interface utilisateur, la logique et les données qui contrôlent l'interface. Le code est plus clair, il sera plus facile à tester.
  • Une description déclarative de l'interface. Le programmeur a seulement besoin de savoir comment décrire ce qu'il veut voir à l'écran, et non comment accéder au DOM afin de donner à la page d'application l'apparence souhaitée.

Les bibliothèques Vue et jQuery ont presque la même taille (en kilo-octets). Bien sûr, la taille de jQuery peut être réduite en utilisant notre propre assemblage de bibliothèque, mais même dans des projets relativement simples, comme notre exemple de compte électronique, je pense que la facilité de développement et la lisibilité du code justifient une légère augmentation de la taille de l'application.

De plus, les capacités de Vue sont beaucoup plus larges que celles que nous avons décrites ici. La force de ce cadre réside dans le fait qu'il vous permet de créer des composants d'interface utilisateur modulaires et réutilisables à partir desquels vous pouvez créer des applications clientes complexes.

Si vous êtes intéressé par le sujet du développement d'applications Web sur Vue, jetez un œil à ce matériel . De plus, si vous envisagez de déplacer des projets de JS pur vers Vue, voici notre récente publication sur ce sujet.

Chers lecteurs! Utilisez-vous jQuery? Et, si vous l'utilisez, prévoyez-vous de changer cette bibliothèque en autre chose, par exemple - en Vue?

Source: https://habr.com/ru/post/fr414073/


All Articles