Portando seu aplicativo Web do JavaScript puro para o Vue.js

Vue.js é uma estrutura de desenvolvimento de aplicativos da web. Possui um sistema de reatividade que permite ao desenvolvedor simular o estado do aplicativo e gerenciá-lo. Como resultado, quando os dados mudam, eles refletem automaticamente na interface do usuário, enquanto o desenvolvedor não precisa acessar o DOM. Se você criar aplicativos usando JavaScript puro ou jQuery, isso significa que é necessário acessar explicitamente os elementos DOM e atualizá-los para refletir as alterações no estado do aplicativo na interface, por exemplo, exibir alguns dados em uma página da web.


No caso de grandes projetos, gerenciar manualmente a sincronização do estado e da interface do aplicativo não é uma tarefa fácil. O autor do material, cuja tradução apresentamos hoje, deseja compartilhar alguns resultados de sua pesquisa, que visa comparar duas versões de um aplicativo da web progressivo usando o Hoodie , que é uma lista de compras . A versão básica deste aplicativo está escrita em JS puro ( neste artigo, você pode encontrar detalhes sobre ele). Aqui, a tradução do aplicativo para Vue.js será mostrada com um exame das características básicas dessa estrutura e com uma análise do que aconteceu no final.


Aplicação pronta

Se vocĂŞ deseja trabalhar com esse material, pode fazer o download do cĂłdigo-fonte do aplicativo em JS puro e seguir o autor, processando-o usando o Vue.

Adicionando produtos Ă  lista


â–ŤJavaScript


O aplicativo permite ao usuário adicionar produtos à sua lista de compras. Isso é feito no arquivo index.html na pasta pública . A marcação está contida nas linhas 92-124 deste arquivo. Lá está ela.

 <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> 

O código para processar e salvar dados está no arquivo public/js/src/index.js . A função saveItems() na linha 28 é responsável por coletar os valores dos controles usados ​​para inserir dados e salvar esses dados. Esta função está vinculada ao evento click do click add-item . Aqui está o código em questão.

 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


Antes de começar a refazer este projeto usando o Vue, você precisa conectar a estrutura à página. No nosso caso, no arquivo index.html , isso é feito da seguinte maneira:

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

Além disso, um elemento <div> foi adicionado ao app identificador, que incluirá todos os elementos da página localizados dentro da tag body . Isso ocorre porque, quando a instância do Vue é inicializada, a estrutura precisa ser informada sobre qual parte da página ela deve gerenciar. Nesse caso, informamos à estrutura que ela deve lidar com tudo o que está nesse bloco.

Agora vamos começar a traduzir o projeto para o Vue. Primeiro, modificamos a marcação para usar algumas diretivas do Vue. As diretivas Vue são atributos especiais prefixados com v- . Aqui está a aparência da marcação atualizada.

 <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> 

A diretiva v-on usada aqui é usada para escutar eventos DOM. No trecho de código acima, ele é usado no elemento de formulário para escutar o evento de submit . Além disso, ele usa o modificador .prevent , que informa à diretiva v-on para chamar event.preventDefault() no evento chamado. Usamos a diretiva v-model para elementos usados ​​para entrada de dados. É necessário, conforme aplicado para formar elementos, criar uma ligação de dados bidirecional. Isso permite que o sistema selecione automaticamente a maneira correta de atualizar um item com base em seu tipo. Usamos o modificador .number para os elementos de cost e quantity .

Isso converte automaticamente o tipo de valor do campo de entrada em um número. Isso é feito porque, mesmo que o tipo esteja definido como type=number , o valor sempre será retornado como uma sequência. Os modificadores usados ​​aqui automatizam a execução de verificações adicionais que anteriormente precisavam ser executadas independentemente.

Em seguida, crie um novo arquivo, index-vue.js , no qual colocamos o código equivalente ao código em index.js , mas usando os recursos do Vue. O código para este arquivo é mostrado abaixo. Isso cria uma instância do Vue com as propriedades necessárias para processar eventos de formulário e coletar dados.

 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"       });     }   } } }); 

Uma instância do Vue foi criada nesse trecho de código e um objeto foi passado para ele, informando ao Vue como configurar o aplicativo. A propriedade el informa à estrutura o identificador do elemento DOM, cujo conteúdo será controlado pelo Vue, considerando-o seu "território". É nesse elemento que o Vue considera as diretivas específicas da estrutura (e tudo mais relacionado ao Vue) e, no processo de inicialização da estrutura, ele configura as ligações e os manipuladores de eventos para o aplicativo.

A propriedade data contém o estado do aplicativo. Todas as propriedades no objeto que está disponível aqui serão, ao inicializar o Vue, adicionadas ao sistema de responsividade da estrutura. São as ações desse sistema que levam à atualização da interface do usuário ao alterar os valores associados ao DOM. Por exemplo, a propriedade name é vinculada ao controle de name usando a diretiva v-model="name" . Esta diretiva define a ligação de dados bidirecional entre a propriedade e o controle de forma que, quando algo é adicionado ao campo de entrada (ou algo é removido dele), a propriedade name é atualizada. Como resultado, o conteúdo do campo de entrada reflete o estado atual da propriedade name .

Da mesma forma, a ligação funciona com outros controles.

A propriedade methods contém funções. No código acima, a função onSubmit() é onSubmit() , anexada ao evento do formulário submit() .

Exibindo dados salvos em uma página


â–ŤJavaScript


A função onSubmit salva dados em um capuz. Depois disso, precisamos exibir, na forma de uma tabela, os itens adicionados à loja. No caso de um aplicativo escrito em JS regular, a marcação correspondente é semelhante a esta:

 <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> 

A tabela conterá dados adicionados dinamicamente, então aqui precisamos de uma maneira de substituir os espaços reservados por dados reais e anexar o que aconteceu ao DOM. No nosso caso, esse problema é resolvido usando micromodelos.

O código a seguir mostra os elementos na interface do usuário à medida que são adicionados.

 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); 

Nesse fragmento de código, o modelo é obtido do DOM, os espaços reservados são substituídos por dados reais e o resultado é anexado ao DOM. Em seguida, é calculado o indicador de total-cost , o valor total para todos os elementos da lista, que também é exibido na interface.

â–ŤVue


Ao mudar para o Vue, o modelo usado pelo script foi excluído e os elementos da tabela foram reformulados para que eles usassem a diretiva Vue v-for , que permite percorrer uma propriedade que contém os dados dos elementos. É assim que a marcação correspondente agora se parece.

 <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> 

De fato, não foram feitas grandes mudanças na marcação. Aqui, o conteúdo do micro-modelo usado anteriormente é copiado e as diretivas e mecanismos de interpolação do texto do Vue são usados. A diretiva v-for é usada para listar os itens cujos dados foram obtidos da propriedade de items . Os dados são exibidos em colunas usando os recursos da construção Vue {{ item.name }} . Esse mecanismo é semelhante aos espaços reservados usados ​​no micro-modelo. O valor total também é exibido na página usando a tecnologia de interpolação de texto.

Agora vamos finalizar o cĂłdigo JavaScript no index-vue.js e obter o seguinte.

 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)); 

Uma variante do mecanismo descrito, preparada por Vue, acabou sendo muito mais curta e mais simples do que o que foi criado usando JS comum. Nesse código, a propriedade de dados dos items foi adicionada, usada na diretiva v-for mencionada acima. Quando um item é adicionado, o Hoodie chama uma função que executa a vm.items.push(item) para atualizar o estado do aplicativo e, graças ao sistema de reatividade Vue, atualiza automaticamente a interface do usuário. Para calcular o valor total, não há necessidade de se referir aos elementos DOM. Aqui, usamos uma propriedade computada que processa o conjunto de dados dos items usando a função .reduce() . Agora, graças ao sistema de reatividade Vue, a interface do usuário é atualizada quando esses valores mudam. O bom é que tudo isso permite que o programador não se preocupe em trabalhar com elementos DOM no código. Como resultado, com a ajuda de um código menor, resolvemos o mesmo problema, que exigia muito mais código no caso de JS comum (provavelmente, se em vez de JS comum nessa situação a biblioteca jQuery fosse usada, o gato também sairia com um tamanho maior, que você adquiriu ao usar o Vue).

Salvando itens como uma lista


â–ŤJavaScript


Após adicionar elementos, é necessário salvá-los para uso posterior, para que posteriormente você possa adicionar outras listas de elementos ao sistema. O aplicativo possui um botão Save List , responsável por coletar dados, salvá-los como um grupo de elementos usando o Hoodie e permitir que o usuário adicione um novo conjunto de elementos ao sistema.

Ao usar JavaScript comum, a função correspondente é vinculada ao onClick botão onClick . Aqui está a marcação.

 //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> 

Aqui está o código da função.

 //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


Mudar para o Vue não exigirá muita alteração. Ainda precisamos vincular o manipulador ao evento que é acionado quando o botão é clicado. Além disso, precisamos adicionar o método, que é o manipulador desse evento, à propriedade de methods do objeto Vue quando ele é inicializado.

É assim que a marcação ficará agora.

 <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> 

A construção @click="saveList" é uma abreviação de v-on:click="saveList" . Este mecanismo é usado para escutar eventos DOM. A mesma função saveList que foi usada na versão do aplicativo gravada em JS puro é adicionada à propriedade de saveList do objeto Vue.

Barra de navegação


â–ŤJavaScript


Agora que os elementos podem ser salvos como uma lista, gostaríamos de poder visualizar listas salvas anteriormente com dados sobre o valor total das mercadorias contidas neles. Esta informação será exibida em outra página, será semelhante à mostrada abaixo.


Dados em listas de produtos criadas anteriormente

A marcação para esta página está no arquivo public/history.html , o código JS correspondente está no arquivo public/js/src/history.js . Esta página e index.html têm algo em comum. Esta é uma barra de navegação localizada na parte superior da janela. Este painel contém links para páginas diferentes, links de Login e Register que invocam formulários de diálogo para entrar no sistema e se registrar nele. Há também um botão Signout para fazer logout.
Na versão do aplicativo criada usando JS comum, era necessário duplicar a mesma marcação nas duas páginas. É assim que o código HTML da barra de navegação se parece.

 <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> 

Após analisar esse código, você notará que, quando clicar nos links Login , Register e Logout , suas funções correspondentes serão chamadas. Manipuladores de eventos para os elementos descritos nesta marcação são definidos no arquivo index.js .

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

As funções responsáveis ​​pelo trabalho com a barra de navegação são declaradas no arquivo 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 }; 

Este código exporta as funções que foram usadas no index.js . As showLoginDialog() e showRegisterDialog() mostram caixas de diálogo modais, respectivamente, para efetuar login e registrar-se nele. A função signout() permite que o usuário efetue logout e chame a função showAnonymous() , que oculta o link Logout e mostra apenas os links Register e Login . A função updateDOMLoginStatus() verifica se o usuário está autenticado e exibe os links apropriados. Esta função é chamada quando a página é carregada.

Para ter a mesma barra de navegação em duas páginas diferentes, tivemos que duplicar a marcação, acessar os elementos DOM e usar os recursos CSS para mostrar e ocultar os links no painel. Vejamos uma barra de navegação alternativa criada pelo Vue.

â–ŤVue


Muitos aplicativos da web têm os mesmos snippets usados ​​em páginas diferentes. Por exemplo, barras de navegação. Tais entidades devem ser colocadas em contêineres ou apresentadas como componentes adequados para reutilização. O Vue fornece ao desenvolvedor um mecanismo de componente que pode ser usado para resolver problemas como o que estamos considerando. Os componentes do Vue são independentes e reutilizáveis.

Transferindo o projeto para usar os componentes do Vue, criamos um novo arquivo, 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 , 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">     <!-- 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 .

Sumário


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

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

, JS. — , Vue.

Caros leitores! - ?

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


All Articles