Migrando do jQuery para o Vue.js

O autor do artigo, cuja tradução publicamos hoje, acredita que há muito mais programadores no mundo que, quando precisam desenvolver um aplicativo Web simples, recorrem ao jQuery . Normalmente, isso acontece quando uma determinada página precisa ser equipada com recursos interativos simples, mas usar algum tipo de estrutura JavaScript para isso parece um exagero. Afinal, são kilobytes de código desnecessário, modelos, ferramentas para construção de projetos, ferramentas para empacotar módulos ... Ao mesmo tempo, conectar-se a uma página jQuery usando um recurso CDN é tão fácil quanto descascar peras.



Este artigo discutirá como converter um projeto criado usando jQuery para Vue.js. Este projeto será criado no jQuery e redesenhado usando o Vue. O autor do material deseja demonstrar a todos que o uso do Vue, mesmo em projetos relativamente pequenos, não significa necessariamente um aumento excessivo no tamanho do código desses projetos e uma grande carga adicional para o programador. Isso, pelo contrário, com quase o mesmo tamanho de código auxiliar que ao usar o jQuery, permite aumentar a produtividade e melhorar a qualidade dos aplicativos.

Visão Geral do Projeto


Vamos desenvolver uma conta eletrônica simples com base neste modelo de código aberto da Sparksuite.

Geralmente, esses estudos de caso usam todos os tipos de listas de tarefas. Espero que um afastamento dessa tradição torne a história mais atual e interessante e, ao mesmo tempo, nossa tarefa seja difícil o suficiente para demonstrar as vantagens de usar algo como o Vue para o desenvolvimento de pequenos projetos. O manual foi projetado para que todos, sem dificuldades especiais, possam reproduzi-lo e dominar os métodos de trabalho propostos.

Aqui está o modelo de conta com o qual queremos trabalhar.


Fatura eletrônica

Nós vamos adicionar recursos interativos, possibilitando a escolha de um produto, sua quantidade e preço unitário. Ao alterar os valores, o custo total das mercadorias e o valor total do documento serão recalculados. Além disso, adicionaremos um botão aqui que permite inserir novas linhas vazias na conta.

Modifiquei o modelo convertendo o código HTML da string vazia no seguinte formato:

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

Desenvolvimento de projeto JQuery


Primeiro, vamos ver como resolver nosso problema usando o jQuery.

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

Conectamos o ouvinte de eventos à tabela. Esse ouvinte chamará a função calculateTotals quando os valores correspondentes ao custo unitário do produto ou sua quantidade forem alterados:

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

A função pega as linhas da tabela e as percorre, passando cada uma das linhas para a função calculSubtotal e somando os resultados. O resultado do cálculo cai na constante constante. Como resultado, o valor total do documento é substituído no campo correspondente da conta.

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

Nesse código, fazemos referência a todos os campos <input> presentes na linha e multiplicamos os valores armazenados no segundo e terceiro campos para obter o valor do subtotal . Então esse valor é inserido na última célula da linha. formatAsCurrency esse valor usando a função formatAsCurrency . Aqui está o código dela:

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

Além disso, temos uma pequena função auxiliar que usamos para garantir a mesma aparência dos campos com os valores para mercadorias e para o documento como um todo. Ou seja, precisamos ter o sinal $ na frente dos números nesses campos e que sejam números decimais com duas casas decimais.

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

E, finalmente, temos um manipulador de eventos para clicar no botão Add row , que serve para adicionar uma nova linha ao documento. Aqui, pegamos a última linha da tabela que contém os dados do produto e fazemos uma cópia deles. Ao mesmo tempo, inserimos dados padrão nos campos dessa nova linha. Além disso, podemos cuidar da conveniência do usuário e focar no primeiro campo de uma nova linha, o que permitirá ao usuário, imediatamente após adicionar uma nova linha, começar a inserir dados em seu primeiro campo.

Aqui está um exemplo de trabalho de uma conta cujos recursos interativos são implementados usando as ferramentas jQuery.

Desvantagens da solução baseada em jQuery


Vamos nos perguntar quais são as desvantagens da abordagem acima, ou melhor, como melhorar nosso projeto.

Talvez você já tenha ouvido falar de novas bibliotecas, como Vue e React, que permitem trabalhar de maneira declarativa e não imperativa. Se você observar o código do jQuery acima, fica claro que ele é lido principalmente como um conjunto de instruções que descrevem a manipulação do DOM. O objetivo de cada seção deste código, isto é, a resposta para a pergunta do que ele faz, geralmente é bastante difícil de entender, olhando como ele o faz. Obviamente, você pode tornar mais claras as intenções dos fragmentos de código usados, dividindo-as em funções com nomes cuidadosamente escolhidos. No entanto, se você deixar esse código por um tempo e depois retornar a ele novamente, acontece que, para entendê-lo, você ainda precisará fazer alguns esforços.

Outro problema com esse código é que o estado do aplicativo é armazenado no DOM. As informações sobre os produtos que o usuário deseja solicitar existem apenas como parte da marcação HTML na interface do usuário. Se tudo o que precisamos é produzir dados em um só lugar, esse problema não parece tão sério. No entanto, assim que for necessário exibir esses dados em vários locais do aplicativo, somos confrontados com a tarefa de sincronizar dados. Sem, como no nosso caso, uma única fonte de dados confiáveis, é muito difícil mantê-los atualizados em todo o aplicativo.

Ao usar o jQuery, nada nos impede de armazenar o estado do aplicativo fora do DOM e evitar o problema descrito acima, bibliotecas como o Vue fornecem recursos que ajudam a criar aplicativos com uma boa arquitetura. Essas bibliotecas ajudam o programador a escrever um código mais limpo e mais estruturado.

Tradução do Projeto no Vue


Agora vamos falar sobre como recriar a mesma funcionalidade no Vue. Para tirar proveito dos recursos do Vue, basta conectar esta biblioteca a uma página da web comum, assim como você faz com o jQuery. Ou seja, não há necessidade de usar o sistema para empacotar módulos ou um transpiler; você não precisa dividir o aplicativo em componentes e decompor seu código em arquivos .vue.

Começamos a traduzir o projeto no Vue, substituindo o conteúdo da <script> :

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

O próximo passo é criar uma nova instância do Vue:

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

O único parâmetro a ser passado para o construtor da nova instância do Vue é el . Este é um seletor (o mesmo usado no jQuery) que identifica a parte do documento que queremos controlar com o Vue.

Podem ser atribuídas tarefas ao Vue de vários tamanhos - desde o gerenciamento de uma página inteira (no caso de, por exemplo, um aplicativo de página única) até um pequeno fragmento fechado em uma <div> . No nosso exemplo, o Vue será responsável por trabalhar com a tabela HTML.

Dados


Adicione dados condicionais para três linhas do documento à instância do Vue:

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

A propriedade data é onde armazenamos o estado do aplicativo. O estado inclui não apenas os dados com os quais nosso aplicativo deve funcionar, mas também informações sobre o estado da interface do usuário (por exemplo, qual seção do aplicativo, composta por várias guias, está ativa no momento ou se um determinado widget é minimizado, como um "acordeão" ou expandido).

O Vue ajuda a manter o estado do aplicativo separado de sua apresentação (ou seja, do DOM) e ajuda a armazenar centralmente o estado em um local, que é uma fonte única de dados confiáveis.

Modificação do modelo


Agora configure o modelo para que ele exiba os dados armazenados no objeto de data . Como dissemos à estrutura que queríamos trabalhar com uma tabela usando uma instância do Vue, podemos usar a sintaxe do modelo do Vue no código HTML que descreve essa tabela para informar ao Vue como renderizar a tabela e como usá-la trabalhar.

Usando o atributo v-for , podemos inferir um bloco de código HTML para cada elemento da matriz de items :

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

O Vue repetirá essa marcação para cada elemento da matriz (ou objeto) que é passado para v-for . Isso nos permite fazer referência a cada elemento no loop. Nesse caso, esse elemento é representado pela variável do item . Como o Vue supervisiona as propriedades do objeto de data , a estrutura atualiza dinamicamente a marcação quando o conteúdo da matriz de items alterado. Tudo o que precisamos fazer é modificar o estado adicionando ou removendo elementos, e o Vue atualizará automaticamente a interface do usuário.

Além disso, precisamos adicionar campos de entrada que o usuário pode preencher inserindo uma descrição do produto, preço unitário, quantidade:

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

Aqui, usamos o atributo v-model para configurar a ligação de dados bidirecional entre campos e propriedades de entrada no modelo de dados. Isso significa que a alteração dos dados nos campos de entrada levará à alteração no modelo e vice-versa.

Na última célula, usamos chaves {{}} , usamos para exibir texto. Você pode usar qualquer expressão JavaScript ativa entre parênteses. Nesse caso, multiplicamos as duas propriedades do elemento e produzimos o que aconteceu. Mais uma vez, o Vue supervisiona o modelo de dados; a alteração de qualquer propriedade recontará automaticamente a expressão.

Eventos e Métodos


Agora, temos um modelo pronto para exibir a coleção de items e somos confrontados com a questão de como adicionar novas linhas à tabela. Como o Vue produzirá tudo o que está na matriz de items para a página, para exibir uma string vazia na página, basta passar o objeto Vue com quaisquer valores que devem estar presentes na matriz de items .

Para criar uma função que pode ser acessada a partir do modelo, você precisa passar essa função para a instância do Vue como uma propriedade do objeto de methods :

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

addRow método addRow , que pode ser chamado para adicionar um novo item à matriz de items :

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

Observe que qualquer método que criarmos será automaticamente vinculado à instância do Vue, o que nos permitirá acessar as propriedades do objeto de data e outros métodos como propriedades this partir desses métodos.

Então agora temos um método. Como chamá-lo clicando no botão Add row ? Para adicionar ouvintes de eventos aos controles em um modelo, o Vue usa a sintaxe v-on:event-name .

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

O Vue também fornece um atalho para a construção v-on :, que se parece com @ . É usado no snippet de código acima. Você pode usar qualquer método da instância do Vue como manipulador de eventos.

Propriedades computadas


Agora basta retirar o valor total do documento na parte inferior da fatura. Isso pode ser feito no próprio modelo. Como já mencionado, o Vue permite que você coloque expressões JS funcionais em construções de colchetes. No entanto, é muito melhor aderir a uma abordagem na qual apenas uma lógica muito simples e nada mais são armazenadas no modelo. Se a lógica for separada do modelo, o código será mais limpo, será mais fácil testar.

Para esse fim, podemos usar o método usual, mas acredito que, neste caso, a chamada propriedade computada seja a melhor para nós. Trabalhar com essas propriedades se assemelha ao trabalho acima com métodos. Ou seja, para criar essas propriedades, um objeto computed é passado para a computed do Vue, contendo funções cujos resultados de execução queremos usar no modelo:

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

Agora a propriedade calculada pode ser referenciada no modelo:

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

Como você deve ter notado, as propriedades calculadas no modelo funcionam como se fossem dados. Nesse caso, você não precisa "chamar" nada no modelo. O uso de propriedades calculadas tem outra vantagem. O Vue é um sistema bastante inteligente, ele armazena em cache os valores retornados e os reconta apenas se as propriedades das quais dependem os valores das propriedades calculadas forem alteradas.

Se usássemos o método para calcular o valor total do documento, os cálculos seriam realizados sempre que o modelo fosse impresso. Porém, como usamos a propriedade calculada, o valor total é recalculado apenas ao alterar os valores de quantity ou price nas linhas da tabela.

Filtros


Você deve ter notado que há um pequeno erro na implementação do nosso projeto criado usando o Vue. Consiste no fato de que, quando os preços de mercadorias individuais são expressos em números inteiros, os valores calculados dos valores totais em linhas e o valor total no documento são exibidos como valores inteiros em dólares, sem centavos. Gostaríamos, como no exemplo do jQuery, esses números sempre contêm duas casas decimais.

Em vez de modificar o código responsável pelo cálculo do valor total da linha e o código que calcula o valor total do documento, podemos tirar proveito dos convenientes recursos de formatação de dados do Vue. É sobre filtros.

Como você provavelmente já entendeu, para criar um filtro, basta passar um objeto (neste caso, filters ) com a chave correspondente à instância do Vue:

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

Aqui criamos um filtro muito simples chamado currency . Ele chama a função toFixed(2) para o valor numérico passado a ele e retorna o resultado. Você pode usar esse filtro no modelo da seguinte maneira:

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

Aqui está a implementação finalizada do nosso projeto no Vue.

Sumário


Se você comparar duas versões do projeto, uma criada usando jQuery e a segunda escrita no Vue, você perceberá os seguintes pontos fortes do aplicativo baseado no Vue:

  • Uma separação clara entre a interface do usuário, a lógica e os dados que controlam a interface. O código é mais claro, será mais fácil testar.
  • Uma descrição declarativa da interface. O programador precisa apenas cuidar de como descrever o que deseja ver na tela, e não de como acessar o DOM para dar à página do aplicativo a aparência desejada.

As bibliotecas Vue e jQuery têm quase o mesmo tamanho (em kilobytes). Obviamente, o tamanho do jQuery pode ser reduzido usando nosso próprio conjunto de bibliotecas, mas mesmo em projetos relativamente simples, como o exemplo de uma conta eletrônica, acredito que a facilidade de desenvolvimento e a legibilidade do código justificam um ligeiro aumento no tamanho do aplicativo.

Além disso, os recursos do Vue são muito mais amplos do que aqueles que descrevemos aqui. A força dessa estrutura reside no fato de que ela permite criar componentes modulares e reutilizáveis ​​da interface do usuário a partir dos quais é possível criar aplicativos clientes complexos.

Se você estiver interessado no tópico de desenvolvimento de aplicativos da Web no Vue, consulte este material . Além disso, se você está pensando em mudar projetos de JS puro para Vue, aqui está nossa publicação recente sobre esse assunto.

Caros leitores! Você usa jQuery? E, se você usá-lo, planeja mudar essa biblioteca para outra coisa, por exemplo - para o Vue?

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


All Articles