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êteSi 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"> <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édemmentLe 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"> <span class="mdl-layout-title">Shopping List</span> <div class="mdl-layout-spacer"></div> <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"> <span class="mdl-layout-title">Shopping List</span> <div class="mdl-layout-spacer"></div> <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
,
false
—
Login
Register
. , Vue
v-if
v-else
.
.
@click
—
v-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"> <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"> <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"> <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"> <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"> <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"> <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"> <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"> <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"> <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! - ?
