Prática para iniciantes: Contruindo uma calculadora com JavaScript
Fala pessoal, vamos construir uma calculadora juntos?
Já parou para pensar como uma coisa tão pequena como uma calculadora funciona? Desde o primeiro código que eu escrevi, sempre me perguntei como que a calculadora funcionava, dada a quantidade de operações que ela executa, principalmente as calculadoras científicas. Estou longe de construir uma calculadora com todas as funcionalidades, mas estou aqui para fazer com vocês uma calculadora que faça as quatro operações básicas e armazene os valores obtidos para realizar a próxima operação. No caminho vamos aprender e praticar algumas coisas.
Estrutura HTML
A estrutura HTML será bem simples, vamos separar uma div para a calculadora > um visor + um container para os botões > os 20 * botões. O Código à princípio será assim:
html
<div id="calculadora">
<div id="visor"><span id="visorInfo"></span></div>
<div id="buttonGrid">
<button class="button operadores" value="(">(</button>
<!-- Aqui é para chamar a função de apagar apenas o ultimo valor inserido. -->
<button class="button" onclick="calculadora.apagaUltimoDigito()">DEL</button>
<button class="button operadores" value=")" >)</button>
<button class="button operadores" value="/">÷</button>
<button class="button numeros" value="1">1</button>
<button class="button numeros" value="2">2</button>
<button class="button numeros" value="3">3</button>
<button class="button operadores" value="*">x</button>
<button class="button numeros" value="4">4</button>
<button class="button numeros" value="5">5</button>
<button class="button numeros" value="6">6</button>
<button class="button operadores" value="-">-</button>
<button class="button numeros" value="7">7</button>
<button class="button numeros" value="8">8</button>
<button class="button numeros" value="9">9</button>
<button class="button operadores" value="+">+</button>
<button class="button-ligar" onclick="calculadora.ligarCalculadora()">ON</button>
<button class="button numeros" value="0">0</button>
<button class="button numeros" value=".">,</button>
<!-- Colocar a função que traz o resultado pra tela -->
<button class="button-result" onclick="calculadora.handleOperacoes()" >=</button>
</div>
</div>
Repare que no contexto desde código, separei os botões por operadores e numeros , que depois serão "seguidos" pelo addEventListener para acompanhar quando forem clicados. Ao mesmo tempo, cada botão tem o seu próprio valor atribuido no próprio elemeto.
Estilo
No estilo eu pensei em como poderia transformar o mais real possível, dando efeitos de luz e sombra.
Abusei do box-shadow com o atributo inset para fazer as sombras se projetarem para dentro do elemento, fiquei com o seguinte código:
CSS
#calculadora {
position:relative;
width: 250px;
height: 400px;
background-color: grey;
margin: 0 auto;
padding: 20px;
box-shadow: inset 0 0 15px rgba(0,0,0,0.75);
}
#visor{
width: 90%;
height: 50px;
border: 2px solid black;
margin: 0 auto;
background-color: #5b715d;
box-shadow: inset 0 0 10px rgba(0,0,0,0.75);
display: flex;
justify-content: flex-end;
align-items: center;
font-size: 36px;
}
#visorInfo {
padding: 0 10px;
}
#buttonGrid{
border-top: 1px solid darkgray;
margin: 20px auto;
padding: 20px 0;
display: grid;
grid-template-columns: repeat(4, 1fr);
row-gap: 15px;
vertical-align: middle
}
.button, .button-ligar, .button-result {
text-align: center;
width: 75%;
height: 40px;
margin: 0 auto;
background-color: lightgray;
position: relative;
font-size: 15px;
font-weight: 700;
}
.button-result{
background-color: rgba(200,100,100,1)
}
/* Detalhes para deixar um pouco mais realista. Esta parte não é tão necessária. */
#calculadora::before{
content:'';
height: 100%;
width: 100%;
position:absolute;
top:0;
left:0 ;
z-index: -1;
box-shadow: 0 0 30px rgba(0,0,0,0.75)
}
.button::before, .button-ligar::before ,.button-result::before{
content:'';
height: 125%;
width: 125%;
position:absolute;
top:-2.5px;
left:-5px ;
box-shadow: inset 0 0 5px black
}
.button-result::before{
box-shadow: inset 0 0 40px rgba(100,20,20,0.75);
}
.button:active, .button-ligar:active{
background-color: darkgray;
color: grey
}
.button-result:active{
background-color: rgba(150,20,20,1);
color: white
}
Ao final desta etapa, você deve ter a seguinte tela:
Agora mos ao creme de la creme, as funcionalidades com o JS
Inserindo as funcionalidades
As funcionalidades são as seguintes:
- Ligar a calculadora
- Mostrar os números digitados na tela
- Pegar o resultado e imprimir na tela.
Dito isto nós podemos começar o nosso código construindo a nossa calculadora desta forma:
JavaScript
class Calculadora {
constructor(){
this.operacao;
this.visor;
this.status;
}
}
const calculadora = new Calculadora
A operação será basicamente tudo o que acontece na tela, desde a primeira entrada de número, até o resultado final. Já que nesta operação irá aparecer tanto números quanto operadores que são strings, não poderemos vamos trabalhar apenas com números. Então a operação será uma string, ou um conjunto de string, onde cada string é um valor digitado.
Para evitar que o computador tenha que lidar com algo do tipo > "1" + "+" + "1" + "=" + "2" < vamos inserir todos os valores digitados em uma array e trabalhar com os métodos de manipulação de listas. Então o nosso " this.operacao = [ ]; "
Decido isto, vamos lá no HTML buscar nossas referências e valores.
A princípio eu pensei em criar uma função para cada botão, mas vi que não seria produtivo, então usei o element.addEventListener para escutar o momento que um botão era clicado para pegar o valor dele e jogar para dentro da Calculadora.
const listaDeNumeros = Array.from(document.getElementsByClassName('numeros'))
listaDeNumeros.map((element) => {
element.addEventListener('click', (event) =>{
calculadora.lerValores(event.target.value)
})
})
O interessante neste caso é a necessidade de colocar em cada elemento da lista de botões um eventlistener. A melhor forma de fazer isto é iterando com o método array map. Com o map nós pegamos cada elemento da lista e adicionamos um eventlistener click, este evento, por sua vez chamará a função da calculadora que recebe o "valor" do botão e é aqui que a mágica precisa acontecer. Nós recebemos os valores, e agora?
Recebendo Valores e fazendo operações
Já estamo na reta final e olha que acabamos de começar.
Agora que a calculadora recebeu o valor digitado, ela precisa mostrar na tela (visor é como eu quis chamar aqui) e vamos fazer isto usando o getElementByID. No código teremos algo do tipo:
JavaScript
class Calculadora {
constructor(){
this.operacao = [ ];
this.visor = window.document.getElementById("visorInfo");
this.status;
}
lerValores(valorDigitado) {
}
}
const calculadora = new Calculadora
const listaDeNumeros = Array.from(document.getElementsByClassName('numeros'))
listaDeNumeros.map((element) => {
element.addEventListener('click', (event) =>{
// Aqui estamos chamando a função que lê o valor dentro da calculadora
calculadora.lerValores(event.target.value)
})
})
E a partir de agora se fizermos simplesmente um "this.visor.innerText = valorDigitado", o visor mostrará o que a pessoa digita, mas não armazenará nenhuma informação.
Para resolver isto, vamos pegar cada valor digitado e armazenar no nosso espaço de memória que apelidamos de operação. Damos então um "this.operacao.push(valorDigitado)" e cada novo valor digitado irá para o final da lista. Podemos usar agora o this.visor.innerText = this.operacao para mostrar na tela os valores digitados sempre que um novo valor é digitado.
No entanto, por ser uma array, como bem sabem, os valores são armazenados e separados por vírgula. Para que os valores armazenados sejam exibidos sem vírgula, usamos um método array pouco falado, o "join". Acrecentando o join, ficamos com o seguinte código:
lerValores(valorDigitado) {
this.operacao.push(valorDigitado);
this.visor.innerText = this.operacao.join("");
}
Se você digitar 2+3, no array terá [ "2" , "+", "3"] e com o array.join(""), você tem o return "2+3"
E pronto. Agora tudo que você digitar nos botões irá aparecer no visor. Agora vamos para a etapa principal, que é fazer o cálculo em si. Para este calculo reservamos o botão " = " onde reservamos a função handleOperacoes().
Neste código não tem enrolação, vamos pegar a string digitada, como no exemplo "2+3" e processá-la com a função nativa do JS chamada eval(). Ele basicamente faz operações com strings. Não é um méodo recomendado por questões de segurança no seu código, mas neste pequeno caso de exemplo onde apenas você irá executar o código na sua máquina, não haverá problema.
Feito o disclaimer, faremos o uso da função do seguinte modo:
handleOperacoes() {
let resultado = eval( this.operacao.join("") )
this.visor.innerText = resultado;
this.operacao = [ result ]
}
Muito moleza, certo? Usamos a função que nos dá a resposta sem precisar criar um if para cada tipo de situação. No final, deixa this.operacao = [ result ] para que fique armazenado na memória o ultimo resultado e a partir daí você consiga continuar as operações.
Como desafio para o próximo, eu deixo o desafio da pesso fazer o botão de ligar e que desliga a calculadora se ficar mais de 10 segundos sem dar algum comando.
Thats all folks. Espero que tenham gostado. Vou deixar os links para ver a calculadora no CodePen e do linkedIn.
CodePen: https://codepen.io/xtirian/pen/jOXVqLd
LinkedIn: https://www.linkedin.com/in/mf-cunha/