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 prontaSe 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"> <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 anteriormenteA 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"> <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>
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"> <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 .
Sumário
-, JS, Vue.js. HTML, CSS JavaScript (jQuery), Vue . ES6 , .
Vue , , . , , , Vue. , , Vue .
, JS.
— , Vue.
Caros leitores! - ?
