0

Criando uma Calculadora com Vue.js

William Gonçalves
William Gonçalves
"Vue (pronuncia-se /vjuː/, como view, em inglês) é um framework progressivo para a construção de interfaces de usuário. Ao contrário de outros frameworks monolíticos, Vue foi projetado desde sua concepção para ser adotável incrementalmente. A biblioteca principal é focada exclusivamente na camada visual (view layer), sendo fácil adotar e integrar com outras bibliotecas ou projetos existentes. Por outro lado, Vue também é perfeitamente capaz de dar poder a sofisticadas Single-Page Applications quando usado em conjunto com ferramentas modernas e bibliotecas de apoio." (Site Oficial)
"Foi criado pelo desenvolvedor independente chinês Evan You, após trabalhar para o Google usando o AngularJS em vários projetos. Posteriormente, ele resumiu o pensamento por trás do processo de criação do Vue: "Pensei, e se eu pudesse retirar somente a parte que realmente gostava do Angular e criar algo muito leve?". [9] O primeiro commit ao código-fonte do projeto data de julho de 2013, e o framework foi lançado oficialmente em fevereiro do ano seguinte, em 2014." (Wikipédia)


Você pode saber mais no guia oficial. E se você quer conhecer mais desse framework e criar um projeto completão, do zero, recomendo o curso do Rafael Maia, disponível aqui na plataforma. Foi com o Rafa, aqui pela DIO, que eu dei meus primeiros passos no Vue.js, stack que me abriu a primeira porta no mercado.


Mas vamos em frente.


E por que vamos usar o Vue.js nesse projeto?


Por conta do design com vários botões iguais, vamos usar uma diretiva nativa do Vue.js para iterar uma lista que retornará os botões diretamente no template HTML.


Além disso, para minimizar o código e a manipulação direta dos elementos do DOM, vamos trabalhar as operações dentro dos scripts, exibindo as informações de forma reativa na tela da calculadora.


A intenção é minimizar o HTML e deixar o Vue.js construir a estrutura da página pra nós.


Arquivos necessários


Vamos criar três arquivos, na mesma pasta, para nosso projeto.


  • index.html
  • style.css
  • script.js


O editor de texto fica a seu critério: você pode usar o que se encaixa melhor contigo. :-)


index.html


Vamos começar com o cabeçalho da página:


<!DOCTYPE html>
<html lang="pt-br">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Calculadora em Vue.js</title>
</head>
<body>

</body>
</html>


Importando o Vue.js para o projeto


Uma das grandes vantagens do Vue.js é a facilidade de integração em projetos menores e até em projetos existentes.


Em casos em que vamos utilizar suas funcionalidades em um escopo controlado, sem necessidade de rotas, etc, basta importar o framework, através de uma tag script diretamente em nosso HTML, acima da tag de fechamento </body>.


Além dela, já importamos nosso arquivo script.js.


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


Testando o Vue.js


Para testar o funcionamento do Vue.js, vamos incluir dois elementos temporários, dentro de um container (#app), logo abaixo da tag <body>.


No <h1>, o conteúdo será exibido através da variável message, usando as duplas chaves ({{ }}), que será atribuída a diretiva v-model do input. Essa diretiva serve para manter os dados sincronizados em mão dupla: o input atualiza o dado, assim como o dado, sendo alterado, atualiza o input. Como o nome sugere, o input será um modelo do dado declarado na diretiva.


<body>
  <div id="app">
    <h1>{{ message }}</h1>
    <input type="text" v-model="message">
  </div>


No arquivo script.js iniciaremos nossa instância Vue, relacionando-a a div com id="app", através da propriedade el, além de incluir a variável message na propriedade data, onde devemos declarar nossas variáveis que serão utilizadas na aplicação. Começaremos com uma mensagem padrão.


var app = new Vue({
  el: "#app",
  data: {
    message: "Mas já está reativo? :O",
  },
});


Salvando as alterações, podemos abrir o index.html no navegador e ver o Vue.js funcionando na prática:


Reatividade em Funcionamento


Vamos para o projeto?


index.html


No index.html, começaremos linkando nosso style.css, assim como a fonte que usaremos no nosso app, a ZCOOL QingKe HuangYou, acima da tag de fechamento </head>.


  <link rel="stylesheet" href="style.css">
  <link href="https://fonts.googleapis.com/css2?family=ZCOOL+QingKe+HuangYou&display=swap" rel="stylesheet">
</head>


Mantendo nossa <div id="app">, removemos os elementos de teste e adicionamos a div 'calculator', com uma <textarea> que servirá como tela, além da div para incluirmos nosso logo e de um span, que servirá como base para os botões.


Na <textarea>, incluímos a propriedade readonly, para impedir digitação de valores, além da diretiva v-model relacionada a variável screenValue, que será criada nos scripts.


<div id="app">
    <div class="calculator">
      <textarea type="text " class="screen" v-model="screenValue" name="txt" readonly></textarea>
      <div class="logo"></div>
      <span class="key"></span>
    </div>
  </div>


Em seguida, ainda no HTML, importamos a biblioteca Math.js, de onde usaremos um método para calcular a expressão da tela.


Como a ideia do projeto é explorar algumas funcionalidades do Vue.js, aprofundar nessa funcionalidade tomaria tempo e nos desviaria do foco.

Por isso, vamos aproveitar o que a comunidade nos oferece! :D


Importe a Math.js, acima da importação do Vue.js. Deve ficar assim:


  <script src="https://unpkg.com/mathjs@7.5.1/dist/math.min.js"></script>
  <script src="https://cdn.jsdelivr.net/npm/vue"></script>
  <script src="script.js"></script>
</body>


script.js - variáveis


No script.js, removeremos a mensagem de teste da propriedade data, incluindo as variáveis que serão usadas no nosso app:


  • isLastInputANumber: booleano que mudará sua condição em função das entradas na tela. Serve para controlar a entrada de operadores nas expressões: se o último input for um número, você pode adicionar um operador. Adicionando um operador, a variável mudará seu estado para falso. Isso impedirá que dois operadores sejam adicionados em sequência, o que quebraria a expressão.


  • isResultDisplayed: booleano que mudará sua condição quando o usuário pressionar o botão "=", para exibir o resultado na tela. Ela é usada como controle para a entrada de número: se o resultado estiver na tela e um número for adicionado, o app iniciará uma nova expressão. Caso contrário, o número será adicionado a expressão em andamento.


  • inputValues: um Array com os valores que serão exibidos nos botões. Lembra que criamos um span para o botão? Usaremos um recurso do Vue.js para recriar uma cópia desse span, para cada valor nesse Array.


  • screenValue: o valor exibido na tela. Será onde os dados serão adicionados e a expressão será calculada.


  data: {
    isLastInputANumber: false,
    isResultDisplayed: false,
    inputValues: [
      "C",
      "/",
      "7",
      "8",
      "9",
      "*",
      "4",
      "5",
      "6",
      "-",
      "1",
      "2",
      "3",
      "+",
      "0",
      "00",
      ".",
      "=",
    ],
    screenValue: "",
  },


script.js - funções


Vamos declarar as funções utilizados na nossa aplicação. Elas também são inseridos em uma outra propriedade: a methods. Ela pode ser declarada após a propriedade data, como no exemplo abaixo:


var app = new Vue({
  el: "#app",
  data: {
    // variáveis
  },
  methods: {
    // métodos
  },
});


A primeira função será a clearScreen(), que limpará a tela e retornará a aplicação a seu estado inicial. Note que, por estarmos dentro de um escopo controlado, uma instância do Vue.js, devemos referenciar a localização das variáveis, através do prefixo this..


A segunda função será a inputOperator() que terá inputValue, o operador digitado, como parâmetro. Ela verificará se a última entrada foi um número e, caso positivo, adicionará o operador.


A terceira função será a inputNumber() que terá inputValue, o número digitado, como parâmetro. Ela verificará se o valor na tela é o resultado de uma expressão. Caso verdadeiro, iniciará uma nova expressão com o número digitado. Caso contrário, adicionará o número a expressão em andamento.


E a quarta e última função será a displayResult(), que verificará se há algum valor na tela e, caso positivo, substituirá a expressão exibida pelo seu resultado, através do método evaluate() da biblioteca Math.js.


A propriedade methods ficará assim:


  methods: {
    clearScreen() {
      this.isLastInputANumber = false;
      this.isResultDisplayed = false;
      this.screenValue = "";
    },
    inputOperator(inputValue) {
      if (this.isLastInputANumber) {
        this.screenValue += inputValue;
        this.isLastInputANumber = false;
        this.isResultDisplayed = false;
      }
    },
    inputNumber(inputValue) {
      if (this.isResultDisplayed) {
        this.screenValue = inputValue;
        this.isResultDisplayed = false;
        this.isLastInputANumber = true;
      } else {
        this.screenValue += inputValue;
        this.isLastInputANumber = true;
      }
    },
    displayResult() {
      if (this.screenValue) {
        this.screenValue = math.evaluate(this.screenValue);
        this.isResultDisplayed = true;
      }
    },
  },


index.html - preenchendo o template


Lembra do nosso <span class="key"></span>? Vamos iterar o array inputValues com a diretiva v-for, para criar os botões, além de usar as diretivas v-bind (sobre a classe) e v-on (sobre o evento de click), para preencher dinamicamente as classes e os métodos atribuídos a cada botão.


Como nosso primeiro botão (index = 0 no array) é o 'C', que apaga a tela, ele será atribuído a função clearScreen() e terá duas classes adicionadas: wide, que fará com que ele tenha o dobro do tamanho dos outros botões, e operator, que o deixará com uma cor diferente dos botões padrão.


Nosso último botão (index = 17 no array) é o '=', que exibe o resultado da expressão na tela. A ele, será atribuída a função displayResult(). A classe operator também deverá ser adicionada a ele, mudando sua cor.


A cada quatro posições, a partir do index = 1, temos nossos operadores. Para encontrá-los no array, somaremos '3' ao valor do index, para que possamos usar o operador '%', verificando se a expressão index + 3 % 4 retorna zero como resto de uma divisão. Caso positivo, a posição representa um operador da nossa calculadora. Atribuiremos a função inputOperator(input), onde input é o valor do botão pressionado, além de incluir a classe operator, que mudará a cor do botão.


Caso nenhuma das condições acima sejam verdadeiras, para a posição lida no array inputValues, significa que ela é um número. Com isso, poderemos atribuir a ela a função inputNumber(input), onde input é o valor do botão pressionado. Ela permanecerá com a classe padrão key.


Como dito acima, vamos iterar o array inputValues com a diretiva v-for. Ela retornará cada posição como input, além do seu index, que nos ajudará a verificar as condições descritas acima. Para cada posição, um novo <span> será renderizado com valores, classes e métodos dinâmicos:


<span 
  class="key" 
  v-for="(input, index) of inputValues" 
  v-bind:class="index == 0 || index == 17 || (index + 3) % 4 == 0 
                ? index == 0
                  ? 'operator wide'
                  : 'operator'
                : ''"
  v-on:click="index == 0 ? clearScreen()
              : index == 17 ? displayResult()
              : (index + 3) % 4 == 0 && index != 17 ? inputOperator(input)
              : inputNumber(input)"
>
  {{ input }}
</span>


O funcionamento já poderá ser visto, salvando as alterações e abrindo o index.html no navegador:


Calculadora em Funcionamento


Usando o Dev Tools, é possível ver que os botões foram renderizados dinamicamente:


Árvore DOM - Botões Preenchidos com v-for


style.css - dando um rosto a nossa calculadora


Incluirei as estilizações, passo a passo.

Recomendo que, a cada uma delas, você salve o resultado e veja no navegador, acompanhando a evolução do design.


No nosso arquivo style.css, começamos com os resets de espaçamento, definimos a tela com 100% de altura e definimos a fonte que importamos anteriormente:


* {
  margin: 0;
  padding: 0;
  box-sizing: border-box;
}

html,
body {
  height: 100%;
}

body {
  font-family: "ZCOOL QingKe HuangYou", sans-serif;
}


Em seguida, fazemos nossa div #app ocupar toda a tela, definimos sua cor de fundo e declaramos suas propriedades como flex-container, centralizando a calculadora no centro do app.


#app {
  width: 100%;
  height: 100%;
  padding: 20px 0;
  background: #121212;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
}


Definimos as medidas da calculadora. Usaremos CSS Grid para distribuir os botões. O template do grid será de quatro colunas. Usaremos a função repeat para replicar o valor 1fr quatro vezes.


.calculator {
  width: 320px;
  height: 560px;

  display: grid;
  grid-template-columns: repeat(4, 1fr);
}


Definimos a tela ocupando o espaço de quatro colunas do grid, adicionamos um espaçamento interno, estilizações de borda, cores e o tamanho da fonte, além de impedirmos que ela seja redimensionada, com a propriedade resize:


.calculator .screen {
  grid-column: span 4;
  width: 100%;
  border: 0;
  padding: 10px;

  border-radius: 10px;
  background: #35495e;
  color: #fff;

  font-size: 3em;
  text-align: right;
  resize: none;
  font-family: "ZCOOL QingKe HuangYou", sans-serif;
}


Definimos a área do logo com o ícone do Vue.js. A url utilizada no background foi retirada do site Devicon:


.calculator .logo {
  margin: 4px;

  background: url("https://raw.githubusercontent.com/devicons/devicon/master/icons/vuejs/vuejs-original.svg")
    no-repeat center;
  background-size: 70%;
}


Definimos o padrão dos botões, desde bordas, cores, sombras, até o display flex, alinhando os valores ao centro. Duas transições são inclusas, para os efeitos que virão a seguir.


.calculator .key {
  border-radius: 10px;
  margin: 4px;

  cursor: pointer;
  background: #42b883;
  color: #fff;
  box-shadow: 2px 2px 4px #215c41;

  font-size: 1.5rem;

  display: flex;
  justify-content: center;
  align-items: center;

  transition: transform 0.1s, background-color 0.1s;
}


Adicionamos um efeito para quando o mouse estiver sobre o botão, mudando sua cor...


.calculator .key:hover {
  background: #184430;
}


...além de um efeito para quando o botão for clicado, que fará ele se deslocar em direção a sombra, dando a impressão de que está afundando, quando pressionado.


.calculator .key:active {
  transform: translate(2px, 2px);
}


Por último, incluímos as duas classes adicionais para mudar as cores dos operadores e para aumentar o botão 'C'. Os seletores são declarados da mesma forma que os da classe .key, para que as declarações acima, com as pseudo-classes :hover e :active tenham maior especificidade e sobrescrevam, também, os estilos desses botões com cor padrão diferente.


.calculator .operator {
  background: #276b4c;
}

.calculator .wide {
  grid-column: span 2;
}


E olha que lindinha, nossa calculadora:


Projeto da Calculadora em Vue.js Finalizado


Você pode usar o app através deste link


E aí? Já conhecia o Vue.js? Curtiu criar esse projeto do zero?


Deixe seu comentário e compartilhe com um amigo que queira dar os primeiros passos no Vue.js.


Você pode me acompanhar nas minhas redes sociais:


GitHub

LinkedIn

Dev.to


E conhecer mais sobre mim e meu trabalho no meu site:


mago.link


Nos vemos na próxima! ;-)

0
0

Comentários (4)

1
Patrick Leite

Patrick Leite

13/08/2021 11:31

show!

1
Patrick Leite

Patrick Leite

13/08/2021 11:31

Muito legal William, obrigado por compartilhar esse conhecimento!

1
Alberth Silva

Alberth Silva

27/04/2021 19:11

Vi teu site man, muito foda.

1
Jefferson Silva

Jefferson Silva

27/04/2021 11:19

Muito legar William, obrigado por compartilhar!

Desenvolvedor Front-End e Designer

Brasil