Portage de votre application Web de JavaScript pur vers Vue.js

Vue.js est un cadre de développement d'applications Web. Il dispose d'un système de réactivité qui permet au développeur de simuler l'état de l'application et de la gérer. Par conséquent, lorsque les données changent, elles se reflètent automatiquement sur l'interface utilisateur, tandis que le développeur n'a pas besoin d'accéder au DOM. Si vous créez des applications à l'aide de JavaScript pur ou de jQuery, cela signifie que vous devez accéder explicitement aux éléments DOM et les mettre à jour afin de refléter les changements dans l'état de l'application dans l'interface, par exemple, afficher certaines données sur une page Web.


Dans le cas de grands projets, la gestion manuelle de la synchronisation de l'interface d'état et d'application n'est pas une tâche facile. L'auteur du document, dont nous présentons aujourd'hui la traduction, souhaite partager quelques résultats de ses recherches visant à comparer deux versions d'une application web progressive utilisant Hoodie , qui est une liste de courses . La version de base de cette application est écrite en JS pur (dans cet article vous pouvez trouver des détails à ce sujet). Ici, la traduction de l'application vers Vue.js sera montrée avec un examen de passage des fonctionnalités de base de ce cadre et avec une analyse de ce qui s'est finalement produit.


Application prête

Si vous souhaitez travailler à travers ce matériel, vous pouvez télécharger le code source de l' application en JS pur et suivre l'auteur, le traiter à l'aide de Vue.

Ajout de produits à la liste


▍JavaScript


L'application permet à l'utilisateur d'ajouter des produits à sa liste de courses. Cela se fait dans le fichier index.html dossier public . Le balisage est contenu dans les lignes 92-124 de ce fichier. Elle est là.

 <div> <div class="mdl-grid center-items"> <div class="mdl-textfield mdl-js-textfield mdl-textfield--floating-label">     <input class="mdl-textfield__input" type="text" id="new-item-name">     <label class="mdl-textfield__label" for="new-item-name">Item Name</label> </div> <div class="mdl-textfield mdl-js-textfield mdl-textfield--floating-label">     <input class="mdl-textfield__input" type="number" id="new-item-cost">     <label class="mdl-textfield__label" for="new-item-cost">Item Cost</label> </div> <div class="mdl-textfield mdl-js-textfield mdl-textfield--floating-label">     <input class="mdl-textfield__input" type="number" id="new-item-quantity">     <label class="mdl-textfield__label" for="new-item-quantity">Quantity</label> </div> </div> <div class="mdl-grid center-items"> <button id="add-item" class="mdl-button mdl-js-button mdl-button--raised mdl-button--colored">     Add Item </button> </div> </div> 

Le code de traitement et d'enregistrement des données se trouve dans le fichier public/js/src/index.js . La fonction saveItems() de la ligne 28 est chargée de collecter les valeurs des contrôles utilisés pour entrer les données et d'enregistrer ces données. Cette fonction est liée à l'événement click du click d' add-item . Voici le code en question.

 function saveNewitem() { let name = document.getElementById("new-item-name").value; let cost = document.getElementById("new-item-cost").value; let quantity = document.getElementById("new-item-quantity").value; let subTotal = cost * quantity; if (name && cost && quantity) {   hoodie.store.withIdPrefix("item").add({     name: name,     cost: cost,     quantity: quantity,     subTotal: subTotal   });   document.getElementById("new-item-name").value = "";   document.getElementById("new-item-cost").value = "";   document.getElementById("new-item-quantity").value = ""; } else {   let snackbarContainer = document.querySelector("#toast");   snackbarContainer.MaterialSnackbar.showSnackbar({     message: "All fields are required"   }); } } document.getElementById("add-item").addEventListener("click", saveNewitem); 

▍Vue


Avant de commencer à retravailler ce projet à l'aide de Vue, vous devez connecter le framework à la page. Dans notre cas, dans le fichier index.html , cela se fait comme suit:

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

De plus, un élément <div> été ajouté avec l' app identification, qui inclura tous les éléments de page situés à l'intérieur de la balise body . En effet, lorsque l'instance de Vue est initialisée, le framework doit être informé de la partie de la page qu'il doit gérer. Dans ce cas, nous informons le framework qu'il doit traiter tout ce qui se trouve dans ce bloc.

Commençons maintenant à traduire le projet en Vue. Tout d'abord, nous modifions le balisage afin d'utiliser certaines directives Vue. Les directives Vue sont des attributs spéciaux préfixés par v- . Voici à quoi ressemble le balisage mis à jour.

 <form v-on:submit.prevent="onSubmit"> <div class="mdl-grid center-items">   <div class="mdl-textfield mdl-js-textfield mdl-textfield--floating-label">     <input class="mdl-textfield__input" type="text" id="new-item-name" v-model="name">     <label class="mdl-textfield__label" for="new-item-name">Item Name</label>   </div>   <div class="mdl-textfield mdl-js-textfield mdl-textfield--floating-label">     <input class="mdl-textfield__input" type="number" id="new-item-cost" v-model.number="cost">     <label class="mdl-textfield__label" for="new-item-cost">Item Cost</label>   </div>   <div class="mdl-textfield mdl-js-textfield mdl-textfield--floating-label">     <input class="mdl-textfield__input" type="number" id="new-item-quantity" v-model.number="quantity">     <label class="mdl-textfield__label" for="new-item-quantity">Quantity</label>   </div> </div> <div class="mdl-grid center-items">   <button id="add-item" class="mdl-button mdl-js-button mdl-button--raised mdl-button--colored">     Add Item   </button> </div> </form> 

La directive v-on utilisée ici est utilisée pour écouter les événements DOM. Dans l'extrait de code ci-dessus, il est utilisé dans l'élément de formulaire pour écouter l'événement submit . En outre, il utilise le modificateur .prevent , qui indique à la directive v-on d'appeler event.preventDefault() sur l'événement appelé. Nous avons utilisé la directive v-model pour les éléments utilisés pour la saisie de données. Il est nécessaire, appliqué aux éléments de formulaire, de créer une liaison de données bidirectionnelle. Cela permet au système de sélectionner automatiquement la bonne façon de mettre à jour un élément en fonction de son type. Nous avons utilisé le modificateur .number pour les éléments de cost et de quantity .

Cela convertit automatiquement le type de valeur du champ de saisie en nombre. Cela est dû au fait que même si le type est défini sur type=number , la valeur sera toujours renvoyée sous forme de chaîne. Les modificateurs utilisés ici automatisent l'exécution de vérifications supplémentaires qui devaient auparavant être effectuées indépendamment.

Ensuite, créez un nouveau fichier, index-vue.js , dans lequel nous index-vue.js le code équivalent à celui dans index.js , mais en utilisant les capacités de Vue. Le code de ce fichier est indiqué ci-dessous. Cela crée une instance de Vue avec les propriétés nécessaires pour traiter les événements de formulaire et collecter les données.

 const vm = new Vue({ el: "#app", data: {   name: "",   cost: "",   quantity: "" }, methods: {   onSubmit: function(event) {     if (this.name && this.cost && this.quantity) {       hoodie.store.withIdPrefix("item").add({         name: this.name,         cost: this.cost,         quantity: this.quantity,         subTotal: this.cost * this.quantity       });       this.name = "";       this.cost = "";       this.quantity = "";     } else {       const snackbarContainer = document.querySelector("#toast");       snackbarContainer.MaterialSnackbar.showSnackbar({         message: "All fields are required"       });     }   } } }); 

Une instance de Vue a été créée dans cet extrait de code et un objet lui a été transmis, indiquant à Vue comment configurer l'application. La propriété el indique au framework l'identifiant de l'élément DOM, dont le contenu sera contrôlé par Vue, le considérant comme son "territoire". C'est au sein de cet élément que Vue considérera les directives spécifiques au framework (et tout ce qui concerne également Vue) et, dans le processus d'initialisation du framework, il configurera les liaisons et les gestionnaires d'événements pour l'application.

La propriété data contient l'état de l'application. Toutes les propriétés de l'objet disponible ici seront, lors de l'initialisation de Vue, ajoutées au système de réactivité du framework. Ce sont les actions de ce système qui conduisent à la mise à jour de l'interface utilisateur lors du changement de valeurs associées au DOM. Par exemple, la propriété name est liée au contrôle de name à l'aide de la directive v-model="name" . Cette directive définit la liaison de données bidirectionnelle entre la propriété et le contrôle de telle manière que lorsque quelque chose est ajouté au champ de saisie (ou que quelque chose en est supprimé), la propriété name est mise à jour. Par conséquent, le contenu du champ de saisie reflète l'état actuel de la propriété name .

De même, la liaison fonctionne avec d'autres contrôles.

La propriété methods contient des fonctions. Dans le code ci-dessus, la fonction onSubmit() est onSubmit() , qui est attachée à l'événement de formulaire submit() .

Affichage des données enregistrées sur une page


▍JavaScript


La fonction onSubmit enregistre les données dans un sweat à capuche. Après cela, nous devons afficher, sous la forme d'un tableau, les articles ajoutés au magasin. Dans le cas d'une application écrite en JS standard, le balisage correspondant ressemble à ceci:

 <div class="mdl-grid center-items"> <table id="item-table" class="mdl-data-table mdl-js-data-table mdl-shadow--2dp">   <thead>     <tr>       <th class="mdl-data-table__cell--non-numeric">Item Name</th>       <th class="mdl-data-table__cell--non-numeric">Cost</th>       <th class="mdl-data-table__cell--non-numeric">Quantity</th>       <th class="mdl-data-table__cell">Sub-total</th>       <th class="mdl-data-table__cell--non-numeric">         <button class="mdl-button mdl-js-button mdl-button--icon">           <i class="material-icons">delete</font></i>         </button>       </th>     </tr>   </thead>   <tbody>   </tbody> </table> </div> <div class="mdl-grid center-items"> <div class="mdl-textfield mdl-js-textfield mdl-textfield--floating-label">   <input class="mdl-textfield__input" type="number" id="total-cost" readonly value="0">   <label class="mdl-textfield__label" for="cost">Total Item Cost</label> </div> </div> <script id="item-row" type="text/template"> <tr id='{{row-id}}'>        <td class="mdl-data-table__cell--non-numeric">{{name}}</td>   <td class="mdl-data-table__cell--non-numeric">{{cost}}</td>   <td class="mdl-data-table__cell--non-numeric">{{quantity}}</td>   <td class="mdl-data-table__cell">{{subTotal}}</td>   <td class="mdl-data-table__cell--non-numeric">         <button class="mdl-button mdl-js-button mdl-button--icon mdl-button--colored"         onclick="pageEvents.deleteItem('{{item-id}}')">         <i class="material-icons">remove</font></i>         </button>   </td> </tr> </script> 

La table contiendra des données ajoutées dynamiquement, nous avons donc ici besoin d'un moyen de remplacer les espaces réservés par des données réelles et de joindre ce qui est arrivé au DOM. Dans notre cas, ce problème est résolu à l'aide de micro-modèles.

Le code suivant montre les éléments de l'interface utilisateur au fur et à mesure qu'ils sont ajoutés.

 function addItemToPage(item) { if (document.getElementById(item._id)) return; let template = document.querySelector("#item-row").innerHTML; template = template.replace("{{name}}", item.name); template = template.replace("{{cost}}", item.cost); template = template.replace("{{quantity}}", item.quantity); template = template.replace("{{subTotal}}", item.subTotal); template = template.replace("{{row-id}}", item._id); template = template.replace("{{item-id}}", item._id); document.getElementById("item-table").tBodies[0].innerHTML += template; let totalCost = Number.parseFloat(   document.getElementById("total-cost").value ); document.getElementById("total-cost").value = totalCost + item.subTotal; } hoodie.store.withIdPrefix("item").on("add", addItemToPage); 

Dans ce fragment de code, le modèle est obtenu à partir du DOM, les espaces réservés sont remplacés par des données réelles et le résultat est attaché au DOM. Ensuite, l'indicateur de total-cost est calculé, le montant total pour tous les éléments de la liste, qui est également affiché dans l'interface.

▍Vue


Lors du passage à Vue, le modèle utilisé par le script a été supprimé et les éléments de la table ont été repensés de manière à utiliser la directive Vue v-for , qui vous permet de parcourir une propriété contenant les données des éléments. Voici à quoi ressemble le balisage correspondant.

 <div class="mdl-grid center-items"> <table id="item-table" class="mdl-data-table mdl-js-data-table mdl-shadow--2dp">   <thead>     <tr>       <th class="mdl-data-table__cell--non-numeric">Item Name</th>       <th class="mdl-data-table__cell--non-numeric">Cost</th>       <th class="mdl-data-table__cell--non-numeric">Quantity</th>       <th class="mdl-data-table__cell">Sub-total</th>       <th class="mdl-data-table__cell--non-numeric">         <button class="mdl-button mdl-js-button mdl-button--icon">           <i class="material-icons">delete</font></i>         </button>       </th>     </tr>   </thead>   <tbody>     <tr v-for="item in items" :key="item._id">       <td class="mdl-data-table__cell--non-numeric">{{ item.name}}</td>       <td class="mdl-data-table__cell--non-numeric">{{ item.cost}}</td>       <td class="mdl-data-table__cell--non-numeric">{{ item.quantity}}</td>       <td class="mdl-data-table__cell">{{ item.subTotal}}</td>       <td class="mdl-data-table__cell--non-numeric">         <button @click="deleteRow(item._id)" class="mdl-button mdl-js-button mdl-button--icon mdl-button--colored">           <i class="material-icons">remove</font></i>         </button>       </td>     </tr>   </tbody> </table> </div> <div class="mdl-grid center-items"> <div class="mdl-textfield mdl-js-textfield mdl-textfield--floating-label">   <!-- <input class="mdl-textfield__input" type="number" id="total-cost" readonly value="0">   <label class="mdl-textfield__label" for="cost">Total Item Cost</label> -->   <h4>Total Cost: {{ total }}</h4> </div> </div> 

En fait, des modifications moins importantes n'ont pas été apportées au balisage. Ici, le contenu du micro-modèle précédemment utilisé est copié et les directives et les mécanismes d'interpolation du texte Vue sont utilisés. La directive v-for est utilisée pour répertorier les éléments dont les données ont été extraites de la propriété items . Les données sont affichées dans des colonnes en utilisant les capacités de la construction Vue {{ item.name }} . Ce mécanisme est similaire aux espaces réservés utilisés dans le micro-modèle. Le montant total est également affiché sur la page à l'aide de la technologie d'interpolation de texte.

Nous allons maintenant finaliser le code JavaScript dans le index-vue.js et obtenir ce qui suit.

 const vm = new Vue({ el: "#app", data: {   name: "",   cost: "",   quantity: "",   items: [] }, computed: {   //     total: function() {     // `this`    vm     return this.items.reduce(       (accumulator, currentValue) => accumulator + currentValue.subTotal,       0     );   } }, methods: {   ..... } }); hoodie.store.withIdPrefix("item").on("add", item => vm.items.push(item)); 

Une variante du mécanisme décrit, préparée par Vue, s'est avérée être beaucoup plus courte et plus simple que celle créée à l'aide de JS standard. Dans ce code, la propriété data data a été ajoutée, utilisée dans la directive v-for susmentionnée. Lorsqu'un élément est ajouté, le Hoodie appelle une fonction qui exécute l'opération vm.items.push(item) pour mettre à jour l'état de l'application, et cela, grâce au système de réactivité Vue, met automatiquement à jour l'interface utilisateur. Pour calculer le montant total, il n'est pas nécessaire de se référer aux éléments DOM. Ici, nous utilisons une propriété calculée qui traite l'ensemble de données items à l'aide de la fonction .reduce() . Désormais, grâce au système de réactivité Vue, l'interface utilisateur est mise à jour lorsque ces valeurs changent. La bonne chose est que tout cela permet au programmeur de ne pas se soucier de travailler avec des éléments DOM dans le code. En conséquence, avec l'aide d'un code plus petit, nous avons résolu le même problème, qui nécessitait beaucoup plus de code dans le cas de JS normal (probablement, si au lieu du JS ordinaire dans cette situation la bibliothèque jQuery était utilisée, le chat sortirait également avec une taille plus grande, que celui que vous avez obtenu en utilisant Vue).

Enregistrement d'éléments sous forme de liste


▍JavaScript


Après avoir ajouté des éléments, vous devez les enregistrer pour une utilisation ultérieure, afin de pouvoir ajouter ultérieurement d'autres listes d'éléments au système. L'application dispose d'un bouton Save List , qui est chargé de collecter les données, de les enregistrer en tant que groupe d'éléments à l'aide des outils Hoodie, et pour que l'utilisateur puisse ajouter un nouvel ensemble d'éléments au système.

Lorsque vous utilisez du JavaScript standard, la fonction correspondante est liée à l' onClick bouton onClick . Voici le balisage.

 //index.html <div class="mdl-grid center-items"> <button class="mdl-button mdl-js-button mdl-button--raised mdl-button--colored" onclick="pageEvents.saveList()">   Save List </button> </div> 

Voici le code de fonction.

 //index.js function saveList() { let cost = 0; hoodie.store   .withIdPrefix("item")   .findAll()   .then(function(items) {     for (var item of items) {       cost += item.subTotal;     }     //      hoodie.store.withIdPrefix("list").add({       cost: cost,       items: items     });     //      hoodie.store       .withIdPrefix("item")       .remove(items)       .then(function() {         //          document.getElementById("item-table").tBodies[0].innerHTML = "";         //          var snackbarContainer = document.querySelector("#toast");         snackbarContainer.MaterialSnackbar.showSnackbar({           message: "List saved succesfully"         });       })       .catch(function(error) {         //             var snackbarContainer = document.querySelector("#toast");         snackbarContainer.MaterialSnackbar.showSnackbar({           message: error.message         });       });   }); } window.pageEvents = { deleteItem: deleteItem, saveList: saveList .... }; 

▍Vue


Passer à Vue ne nécessitera pas beaucoup de changements. Nous devons toujours lier le gestionnaire à l'événement qui est appelé lorsque le bouton est cliqué; en outre, nous devons ajouter la méthode, qui est le gestionnaire de cet événement, à la propriété methods de l'objet Vue lors de son initialisation.

Voici à quoi ressemblera le balisage.

 <div class="mdl-grid center-items"> <button @click="saveList" class="mdl-button mdl-js-button mdl-button--raised mdl-button--colored">   Save List </button> </div> 

La construction @click="saveList" est un raccourci pour v-on:click="saveList" . Ce mécanisme est utilisé pour écouter les événements DOM. La même fonction saveList , qui était utilisée dans la version de l'application écrite en JS pur, est ajoutée à la propriété methods de l'objet Vue.

Barre de navigation


▍JavaScript


Maintenant que les éléments peuvent être enregistrés sous forme de liste, nous aimerions pouvoir afficher les listes précédemment enregistrées avec des données sur la valeur totale des marchandises qu'elles contiennent. Ces informations seront affichées sur une autre page, elles ressembleront à celle illustrée ci-dessous.


Données sur les listes de produits créées précédemment

Le balisage de cette page se trouve dans le fichier public/history.html , le code JS correspondant se trouve dans le fichier public/js/src/history.js . Cette page et index.html ont quelque chose en commun. Il s'agit d'une barre de navigation située en haut de la fenêtre. Ce panneau contient des liens vers différentes pages, Register liens de Login et d' Register qui invoquent des formulaires de dialogue pour entrer dans le système et s'enregistrer. Il existe également un bouton de Signout pour vous déconnecter.
Dans la version de l'application créée à l'aide de JS ordinaire, vous deviez dupliquer le même balisage sur les deux pages. Voici à quoi ressemble le code HTML de la barre de navigation.

 <header class="mdl-layout__header">   <div class="mdl-layout__header-row">   <!-- Title -->   <span class="mdl-layout-title">Shopping List</span>   <!-- Add spacer, to align navigation to the right -->   <div class="mdl-layout-spacer"></div>   <!-- Navigation. We hide it in small screens. -->   <nav class="mdl-navigation mdl-layout--large-screen-only">       <a class="mdl-navigation__link" href="index.html">Home</a>       <a class="mdl-navigation__link" href="history.html">History</a>       <a onclick="pageEvents.showLogin()" style="cursor: pointer" class="mdl-navigation__link login">Login</a>       <a onclick="pageEvents.showRegister()" style="cursor: pointer" class="mdl-navigation__link register">Register</a>       <a onclick="pageEvents.signout()" style="cursor: pointer" class="mdl-navigation__link logout">Logout</a>   </nav>   </div> </header> <div class="mdl-layout__drawer">   <span class="mdl-layout-title">Shopping List</span>   <nav class="mdl-navigation">   <a class="mdl-navigation__link" href="index.html">Home</a>   <a class="mdl-navigation__link" href="history.html">History</a>   <a onclick="pageEvents.showLogin()" style="cursor: pointer" class="mdl-navigation__link login">Login</a>   <a onclick="pageEvents.showRegister()" style="cursor: pointer" class="mdl-navigation__link register">Register</a>   <a onclick="pageEvents.signout()" style="cursor: pointer" class="mdl-navigation__link logout">Logout</a>   </nav> </div> 

Après avoir analysé ce code, vous remarquerez que lorsque vous cliquez sur les liens de Login , d' Register et de Logout , leurs fonctions correspondantes seront appelées. Les gestionnaires d'événements pour les éléments décrits dans ce balisage sont définis dans le fichier index.js .

 import * as shared from "shared.js"; .... shared.updateDOMLoginStatus(); window.pageEvents = { showLogin: shared.showLoginDialog, showRegister: shared.showRegisterDialog, signout: shared.signOut }; 

Les fonctions chargées de travailler avec la barre de navigation sont déclarées dans le fichier shared.js .

 //   let loginDialog = document.querySelector("#login-dialog"); dialogPolyfill.registerDialog(loginDialog); let registerDialog = document.querySelector("#register-dialog"); dialogPolyfill.registerDialog(registerDialog); let showLoginDialog = function() { loginDialog.showModal(); }; let showRegisterDialog = function() { registerDialog.showModal(); }; let showAnonymous = function() { document.getElementsByClassName("login")[0].style.display = "inline"; document.getElementsByClassName("login")[1].style.display = "inline"; document.getElementsByClassName("register")[0].style.display = "inline"; document.getElementsByClassName("register")[1].style.display = "inline"; document.getElementsByClassName("logout")[0].style.display = "none"; document.getElementsByClassName("logout")[1].style.display = "none"; }; let showLoggedIn = function() { document.getElementsByClassName("login")[0].style.display = "none"; document.getElementsByClassName("login")[1].style.display = "none"; document.getElementsByClassName("register")[0].style.display = "none"; document.getElementsByClassName("register")[1].style.display = "none"; document.getElementsByClassName("logout")[0].style.display = "inline"; document.getElementsByClassName("logout")[1].style.display = "inline"; }; let updateDOMLoginStatus = () => { hoodie.account.get("session").then(function(session) {   if (!session) {     //          showAnonymous();   } else if (session.invalid) {     //   ,          showAnonymous();   } else {     //         showLoggedIn();   } }); }; let signOut = function() { hoodie.account   .signOut()   .then(function() {     showAnonymous();     let snackbarContainer = document.querySelector("#toast");     snackbarContainer.MaterialSnackbar.showSnackbar({       message: "You logged out"     });     location.href = location.origin;   })   .catch(function() {     let snackbarContainer = document.querySelector("#toast");     snackbarContainer.MaterialSnackbar.showSnackbar({       message: "Could not logout"     });   }); }; export { signOut, showRegisterDialog, showLoginDialog, updateDOMLoginStatus }; 

Ce code exporte les fonctions utilisées dans index.js . Les fonctions showLoginDialog() et showRegisterDialog() affichent des boîtes de dialogue modales, respectivement, pour se connecter et s'enregistrer. La fonction signout() permet à l'utilisateur de se déconnecter et appelle la fonction showAnonymous() , qui masque le lien de showAnonymous() et affiche uniquement les liens d' Register et de Login . La fonction updateDOMLoginStatus() vérifie si l'utilisateur est authentifié et affiche les liens appropriés. Cette fonction est appelée lors du chargement de la page.

Afin d'avoir la même barre de navigation sur deux pages différentes, nous avons dû dupliquer le balisage, accéder aux éléments DOM et utiliser les fonctionnalités CSS afin d'afficher et de masquer les liens sur le panneau. Regardons une autre barre de navigation créée par Vue.

▍Vue


De nombreuses applications Web ont les mêmes extraits de code utilisés sur différentes pages. Par exemple, les barres de navigation. Ces entités devraient être placées dans des conteneurs ou présentées comme des composants pouvant être réutilisés. Vue fournit au développeur un moteur de composants qui peut être utilisé pour résoudre des problèmes comme celui que nous envisageons. Les composants Vue sont autonomes et réutilisables.

Vue , shared-vue.js . Vue, . .

 Vue.component("navigation", { props: ["isLoggedIn", "toggleLoggedIn"], template: `<div>             <header class="mdl-layout__header">       <div class="mdl-layout__header-row">         <!-- Title -->         <span class="mdl-layout-title">Shopping List</span>         <!-- Add spacer, to align navigation to the right -->         <div class="mdl-layout-spacer"></div>         <!-- Navigation. We hide it in small screens. -->         <nav class="mdl-navigation mdl-layout--large-screen-only">           <a class="mdl-navigation__link" href="index.html">Home</a>           <a class="mdl-navigation__link" href="history.html">History</a>           <a v-show="!isLoggedIn" @click="showLogin" style="cursor: pointer" class="mdl-navigation__link login">Login</a>           <a v-show="!isLoggedIn" @click="showRegister" style="cursor: pointer" class="mdl-navigation__link register">Register</a>           <a v-show="isLoggedIn" @click="logout" style="cursor: pointer" class="mdl-navigation__link logout">Logout</a>         </nav>       </div>     </header>     <div class="mdl-layout__drawer">       <span class="mdl-layout-title">Shopping List</span>       <nav class="mdl-navigation">         <a class="mdl-navigation__link" href="index.html">Home</a>         <a class="mdl-navigation__link" href="history.html">History</a>         <a v-show="!isLoggedIn" @click="showLogin" style="cursor: pointer" class="mdl-navigation__link login">Login</a>         <a v-show="!isLoggedIn" @click="showRegister" style="cursor: pointer" class="mdl-navigation__link register">Register</a>         <a v-show="isLoggedIn" @click="logout" style="cursor: pointer" class="mdl-navigation__link logout">Logout</a>       </nav>     </div>           </div>`, methods: {   showLogin: function() {     const loginDialog = document.querySelector("#login-dialog");     dialogPolyfill.registerDialog(loginDialog);     loginDialog.showModal();   },   showRegister: function() {     const registerDialog = document.querySelector("#register-dialog");     dialogPolyfill.registerDialog(registerDialog);     registerDialog.showModal();   },   logout: function() {     hoodie.account       .signOut()       .then(() => {         this.toggleLoggedIn();       })       .catch(error => {         alert("Could not logout");       });   } } }); 

Vue, navigation , , , Vue. — props . props — . , , , props . isLoggedIn , .

, template , , . , , JS, , Vue — v-show @click . v-show . Logout , isLoggedIn true , falseLogin Register . , Vue v-if v-else . . @clickv-on:click . showLogin , showRegister logout .

methods . logout , , this.toggleLoggedIn() , props . , props , , isLoggedin , . , Vue DOM.
index.html . , 59-84. .

 <navigation v-bind:is-logged-in="isLoggedIn" v-bind:toggle-logged-in="toggleLoggedIn"></navigation> 

JS- isLoggedIn toggleLoggedIn , , props , , kebab-case. v-bind . isLoggedIn . : v-bind , .

 <navigation :is-logged-in="isLoggedIn" :toggle-logged-in="toggleLoggedIn"></navigation> 

isLoggedIn , toggleLoggedIn — , Vue index-vue.js . .

 const vm = new Vue({ el: "#app", data: {   name: "",   cost: "",   quantity: "",   items: [],   isLoggedIn: false }, computed: {   .....//   }, methods: {   toggleLoggedIn: function() {     this.isLoggedIn = !this.isLoggedIn;   },   ......//   } }); .....//   hoodie.account.get("session").then(function(session) { if (!session) {   //       vm.isLoggedIn = false; } else if (session.invalid) {   vm.isLoggedIn = false; } else {   //       vm.isLoggedIn = true; } }); 

Vue , , , , Vue. , Vue DOM , .


▍JavaScript


Login Register , . , , , . 171-244 index.html 100-158 history.html .

 <dialog id="login-dialog" class="mdl-dialog"> <h4 class="mdl-dialog__title">Login</h4> <div class="mdl-dialog__content">   <div class="mdl-grid center-items">     <!-- Simple Textfield -->     <div class="mdl-textfield mdl-js-textfield">       <input class="mdl-textfield__input" type="text" id="login-username">       <label class="mdl-textfield__label" for="login-username">Username</label>     </div>   </div>   <div class="mdl-grid center-items">     <!-- Simple Textfield -->     <div class="mdl-textfield mdl-js-textfield">       <input class="mdl-textfield__input" type="password" id="login-password">       <label class="mdl-textfield__label" for="login-password">Password</label>     </div>   </div>   <div class="mdl-grid center-items">     <!-- Simple Textfield -->     <div class="mdl-textfield mdl-js-textfield">       <span id="login-error"></span>     </div>   </div> </div> <div class="mdl-dialog__actions">   <button onclick="pageEvents.closeLogin()" type="button" class="mdl-button close">Cancel</button>   <button onclick="pageEvents.login()" type="button" class="mdl-button">Login</button> </div> </dialog> <dialog id="register-dialog" class="mdl-dialog"> <h4 class="mdl-dialog__title">Login</h4> <div class="mdl-dialog__content">   <div class="mdl-grid center-items">     <!-- Simple Textfield -->     <div class="mdl-textfield mdl-js-textfield">       <input class="mdl-textfield__input" type="text" id="register-username">       <label class="mdl-textfield__label" for="register-username">Username</label>     </div>   </div>   <div class="mdl-grid center-items">     <!-- Simple Textfield -->     <div class="mdl-textfield mdl-js-textfield">       <input class="mdl-textfield__input" type="password" id="register-password">       <label class="mdl-textfield__label" for="register-password">Password</label>     </div>   </div>   <div class="mdl-grid center-items">     <!-- Simple Textfield -->     <div class="mdl-textfield mdl-js-textfield">       <span id="register-error"></span>     </div>   </div> </div> <div class="mdl-dialog__actions">   <button onclick="pageEvents.closeRegister()" type="button" class="mdl-button close">Cancel</button>   <button onclick="pageEvents.register()" type="button" class="mdl-button">Register</button> </div> </dialog> 

, , shared.js index.js .

 //shared.js //   let loginDialog = document.querySelector("#login-dialog"); dialogPolyfill.registerDialog(loginDialog); let registerDialog = document.querySelector("#register-dialog"); dialogPolyfill.registerDialog(registerDialog); let closeLoginDialog = function() { loginDialog.close(); }; let closeRegisterDialog = function() { registerDialog.close(); }; let showAnonymous = function() { ... }; let showLoggedIn = function() { .... }; let signOut = function() { .... }; let updateDOMLoginStatus = () => { .... }; let login = function() { let username = document.querySelector("#login-username").value; let password = document.querySelector("#login-password").value; hoodie.account   .signIn({     username: username,     password: password   })   .then(function() {     showLoggedIn();     closeLoginDialog();     let snackbarContainer = document.querySelector("#toast");     snackbarContainer.MaterialSnackbar.showSnackbar({       message: "You logged in"     });   })   .catch(function(error) {     console.log(error);     document.querySelector("#login-error").innerHTML = error.message;   }); }; let register = function() { let username = document.querySelector("#register-username").value; let password = document.querySelector("#register-password").value; let options = { username: username, password: password }; hoodie.account   .signUp(options)   .then(function(account) {     return hoodie.account.signIn(options);   })   .then(account => {     showLoggedIn();     closeRegisterDialog();     return account;   })   .catch(function(error) {     console.log(error);     document.querySelector("#register-error").innerHTML = error.message;   }); }; export { register, login, closeRegisterDialog, closeLoginDialog, ... }; 

index.js.

 //index.js window.pageEvents = { closeLogin: shared.closeLoginDialog, showLogin: shared.showLoginDialog, closeRegister: shared.closeRegisterDialog, showRegister: shared.showRegisterDialog, login: shared.login, register: shared.register, signout: shared.signOut }; 

▍Vue


Vue . , .

 Vue.component("login-dialog", { data: function() {   return {     username: "",     password: ""   }; }, props: ["toggleLoggedIn"], template: `<dialog id="login-dialog" class="mdl-dialog">     <h4 class="mdl-dialog__title">Login</h4>     <div class="mdl-dialog__content">       <div class="mdl-grid center-items">         <!-- Simple Textfield -->         <div class="mdl-textfield mdl-js-textfield">           <input v-model="username" class="mdl-textfield__input" type="text" id="login-username">           <label class="mdl-textfield__label" for="login-username">Username</label>         </div>       </div>       <div class="mdl-grid center-items">         <!-- Simple Textfield -->         <div class="mdl-textfield mdl-js-textfield">           <input v-model="password" class="mdl-textfield__input" type="password" id="login-password">           <label class="mdl-textfield__label" for="login-password">Password</label>         </div>       </div>       <div class="mdl-grid center-items">         <!-- Simple Textfield -->         <div class="mdl-textfield mdl-js-textfield">           <span id="login-error"></span>         </div>       </div>     </div>     <div class="mdl-dialog__actions">       <button @click="closeLogin" type="button" class="mdl-button close">Cancel</button>       <button @click="login" type="button" class="mdl-button">Login</button>     </div>   </dialog>`, methods: {   closeLogin: function() {     const loginDialog = document.querySelector("#login-dialog");     dialogPolyfill.registerDialog(loginDialog);     loginDialog.close();   },   login: function(event) {     hoodie.account       .signIn({         username: this.username,         password: this.password       })       .then(() => {         this.toggleLoggedIn();         this.closeLogin();       })       .catch(error => {         console.log(error);         document.querySelector("#login-error").innerHTML = "Error loggin in";       });   } } }); 

data , props , template methods , Vue.component() .

, , Vue .

 //index.html <login-dialog v-bind:toggle-logged-in="toggleLoggedIn"></login-dialog> 

.

, , Vue. , , . , - Push API .

Résumé


-, JS, Vue.js. HTML, CSS JavaScript (jQuery), Vue . ES6 , .

Vue , , . , , , Vue. , , Vue .

, JS. — , Vue.

Chers lecteurs! - ?

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


All Articles