Pular para o conteúdo
murad.guide

Introdução Completa à Web

Capítulo 20

Projeto: calculadora

5 min de leitura 975 palavras 2 gravuras

Hora de juntar HTML, CSS e JavaScript numa peça só. A Casa da Restinga ganha uma calculadora de balcão: visual próximo ao telefone clássico, só inteiros. Sem %. Sem vírgula nem ponto decimal. O C zera tudo, como no carregamento da página. Esta é o capítulo 20 de 23.

O exemplo pronto está em exemplos/20-calculadora/. Abra index.html. Os botões são <button>. O layout das linhas é Flex. O cérebro está em calculadora.js.

Trabalhe na cópia inicio da etapa. Leia e digite o código; mude uma coisa. Antes de recarregar, anote sua previsão. Depois confira com a referência completa. Se nada mudar, confira o arquivo salvo e o caminho aberto. Blocos adicionais do capítulo podem ser digitados no console; o exemplo completo mostra a aplicação daquela etapa.

O que você vai aprender

O combinado do balcão

Regras desta calculadora:

A tela deve continuar dentro da página: números longos podem rolar dentro dela.

Pare e experimente. Abra o exemplo. Some 2 + 3 =. Preveja 5. Recarregue. Confira a tela.

Erro comum: começar pelo JavaScript com a grade ainda em div. Sem button, teclado e leitor de tela sofrem. Faça HTML e CSS primeiro.

Calculadora da Restinga: tela, C, inteiros, operadores

HTML: button e linhas

Cada tecla é um <button type="button">. C ocupa duas colunas. 0 ocupa três. O script entra no fim do body.

<!DOCTYPE html>
<html lang="pt-BR">
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <title>Calculadora — Casa da Restinga</title>
  <link rel="stylesheet" href="styles.css">
</head>
<body>
  <main class="calc">
    <section class="tela" aria-live="polite">0</section>
    <section class="botoes">
      <div class="linha">
        <button type="button" class="duplo">C</button>
        <button type="button">←</button>
        <button type="button">÷</button>
      </div>
      <div class="linha">
        <button type="button">7</button>
        <button type="button">8</button>
        <button type="button">9</button>
        <button type="button">×</button>
      </div>
      <div class="linha">
        <button type="button">4</button>
        <button type="button">5</button>
        <button type="button">6</button>
        <button type="button">-</button>
      </div>
      <div class="linha">
        <button type="button">1</button>
        <button type="button">2</button>
        <button type="button">3</button>
        <button type="button">+</button>
      </div>
      <div class="linha">
        <button type="button" class="triplo">0</button>
        <button type="button">=</button>
      </div>
    </section>
  </main>
  <script src="calculadora.js"></script>
</body>
</html>

Há outras marcações possíveis. Esta funciona e o exemplo a usa.

Pare e experimente. Tire o type="button" de uma tecla e recarregue dentro de um form de teste. Preveja um envio. Restaure type="button".

Erro comum: usar <div onclick> no lugar de button. O volume pede button.

CSS: Flex e calha

Cada .linha é display: flex com justify-content: space-between. Largura do botão comum: cerca de 24.5%, para caberem quatro. A calha (vão preto) nas laterais vem desse espaço. Embaixo, margin-bottom: 0.5%: margem percentual mede em relação à largura, então o vão inferior combina com o lateral.

.linha {
  display: flex;
  justify-content: space-between;
  margin-bottom: 0.5%;
}
.botoes button {
  width: 24.5%;
  height: 100px;
  font-size: 2rem;
}
.duplo { width: 49.7%; }
.triplo { width: 74.8%; }
.linha button:last-child {
  background: #9f4b13;
  color: #fff;
}

A tela usa monospace (ou "Courier New"), alinhada à direita. Fundo da caixa: preto. Botões claros; o último de cada linha, laranja.

Pare e experimente. Mude 24.5% para 20%. Preveja um vão maior. Recarregue. Confira. Restaure.

Erro comum: gap grande mais largura 25%. A quarta tecla cai na linha de baixo. Some os percentuais com a calha.

Buffer string, conta number

Tudo que sai do DOM é texto. "5" + "5" vira "55". A conta precisa de número.

console.log(typeof "5");
console.log(parseInt("5", 10) + parseInt("5", 10));

parseInt(texto, 10) lê um inteiro na base 10. Três variáveis de estado:

let total = 0;
let buffer = "0";
let operador = null;
const tela = document.querySelector(".tela");

Enquanto a pessoa digita, você cola dígitos no buffer. Na hora de somar, converte.

Pare e experimente. No console, rode typeof document.querySelector(".tela").textContent. Preveja "string". Confira.

Erro comum: buffer + 5 misturando tipos. Se buffer é "3", vira "35" na concatenação e "8" só se você converter os dois lados na conta.

Um ouvinte e funções pequenas

Vários botões, um pai .botoes. Um click. Funções curtas: uma decide se é número ou símbolo; outra trata dígito; outra trata C, =, ← e operadores.

document.querySelector(".botoes").addEventListener("click", function (evento) {
  const botao = evento.target.closest("button");
  if (!botao) {
    return;
  }
  clicar(botao.textContent.trim());
  tela.textContent = buffer;
});

function clicar(valor) {
  if (Number.isNaN(parseInt(valor, 10))) {
    simbolo(valor);
  } else {
    numero(valor);
  }
}

function numero(valor) {
  if (buffer === "0") {
    buffer = valor;
  } else {
    buffer += valor;
  }
}

O exemplo completo em calculadora.js tem também simbolo e calcular. Cerca de oitenta linhas, não duzentas. Se passar de duzentas, quebre de novo.

Pare e experimente. Clique 7 e 8. Preveja 78 na tela. Recarregue. Confira.

Erro comum: um ouvinte em cada botão copiando a mesma função. Delegue no pai, como no capítulo 19.

Início da referência desta etapa no navegador local

C, operadores e igual

C devolve o estado do carregamento: buffer = "0", total = 0, operador = null.

Quando chega +, -, × ou ÷: transforme o buffer em número; se já havia operação pendente, feche-a; guarde o novo operador; zere o buffer para o próximo dígito.

No =: se não há operador, ignore. Senão aplique, jogue o resultado no buffer, limpe total e operador.

Neste exercício, Math.trunc descarta a parte fracionária da divisão: 5 dividido por 2 dá 2. Isso é uma escolha do exercício, não uma regra da matemática. Divisão por zero mostra Erro; C reinicia.

←: buffer.substring(0, buffer.length - 1). Se o comprimento era 1, buffer = "0".

Pare e experimente. Faça 9 − 4 =, depois C. Preveja 0. Recarregue se o C não limpar o operador.

Erro comum: o C só apagar a tela e deixar operador antigo. O próximo número entra na conta errada.

Atividades

  1. Por que os dígitos ficam no buffer como string?
  2. O que o C precisa zerar além da tela?
  3. Por que as teclas são button e não div?
  4. Onde fica o addEventListener de clique neste projeto?

Respostas comentadas

  1. A pessoa cola dígitos. "7" + "8" deve virar "78", não 15. A conversão é na conta.
  2. buffer, total e operador. Só limpar o texto deixa a operação anterior viva.
  3. Tecla com papel de botão. Foco, Enter e leitor de tela já vêm com button.
  4. No container .botoes, um ouvinte só. closest("button") acha a tecla.

MDN

O arquivo completo

Referência do exemplo 20-calculadora, reproduzida aqui para que você possa conferir sem sair da página.

styles.css

.linha {
  display: flex;
  justify-content: space-between;
  margin-bottom: 0.5%;
}
.botoes button {
  width: 24.5%;
  height: 100px;
  font-size: 2rem;
}
.botoes .duplo { width: 49.7%; }
.botoes .triplo { width: 74.8%; }
.linha button:last-child {
  background: #9f4b13;
  color: #fff;
}
*{box-sizing:border-box}body{font-family:Arial;margin:1rem}.calc{width:25rem;max-width:100%;padding:.5rem;background:#000;color:#fff}.tela{text-align:right;overflow:auto;padding:1rem;font-size:2rem}.botoes button{border:0;color:#111;background:#e7e7e7}.botoes button.op{background:#9f4b13;color:#fff}