Как сделать простой калькулятор на HTML и Javascript

162
29 декабря 2019, 16:40

Я знаю, что похожие вопросы задали ранее. Но всё-таки мне хотелось бы узнать, можно ли написать функцию для калькулятора, опираясь на код, мной написанный до сих пор.

Знаю, как сделать простейший калькулятор для сложения эксклюзивно:

 <input id="num1"/>
 <p>+</p>
 <input id="num2"/>
 <button onclick="func()">равняется...</button>
 <p id="result"></p>
 <script>
    function func(){
          var num1 = Number(document.getElementById("num1").value);
          var num2 = Number(document.getElementById("num2").value);
          var result = num1 + num2;
          document.getElementById("result").innerHTML = result;
          }
 </script>

До сих пор, нет сомнений. Но сейчас, мне хотелось бы заменить статичный знак плюса (+) четырьмя кнопками для всех базовых операций: сложения (+), вычитания (-), умножения (x), деления (:).

Интерфейс и распределения кнопок умею вставить, но не успеваю создать функцию, которая изменяет оператор в переменной result в зависимости от избранной кнопки операции.

Нужно ли делать отдельную функцию для каждой кнопки операторов? Или можно вставить всю программу в функцию кнопки выполнения ("равняется...")?

Вот код, написанный до сих пор:

<input id="num1"/>
<div id="operator_btns">
  <button id="plus" class="operator">+</button>
  <button id="minus" class="operator">-</button>
  <button id="times" class="operator">x</button>
  <button id="divide" class="operator">:</button>
</div>
<input id="num2"/>
<button onclick="func()">равняется...</button>
<p id="result"></p>

<script>
  function func(){
    var num1 = Number(document.getElementById("num1").value);
    var num2 = Number(document.getElementById("num2").value);
    result = ???
    document.getElementById("result").innerHTML = result;
    }
</script>

Какой будет функция переменной result? Спасибо за помощь!

Answer 1

Вариантов много. Например, при нажатии на кнопку оператора, соответствующе устанавливаем переменную текущего оператора. Затем, при нажатии на кнопку равняется считаем результат в зависимости от текущего оператора.

<input id="num1" /> 
 
<div id="operator_btns"> 
  <button id="plus" class="operator" onclick="op='+'">+</button> 
  <button id="minus" class="operator" onclick="op='-'">-</button> 
  <button id="times" class="operator" onclick="op='*'">x</button> 
  <button id="divide" class="operator" onclick="op='/'">:</button> 
</div> 
 
<input id="num2" /> 
 
<button onclick="func()">равняется...</button> 
 
<p id="result"></p> 
 
 
<script> 
  var op; //выбранный оператор 
  function func() { 
    var result; 
    var num1 = Number(document.getElementById("num1").value); 
    var num2 = Number(document.getElementById("num2").value); 
    switch (op) { 
      case '+': 
        result = num1 + num2; 
        break; 
      case '-': 
        result = num1 - num2; 
        break; 
      case '*': 
        result = num1 * num2; 
        break; 
      case '/': 
        if (num2) { 
          result = num1 / num2; 
        } else { 
          result = 'бесконечность'; 
        } 
        break; 
      default: 
        result = 'выберите операцию'; 
    } 
 
    document.getElementById("result").innerHTML = result; 
  } 
</script>

Answer 2

В отдельной функции для каждой операции, смысла нет - потому что при смене операции в интерфейсе, в алгоритме меняется всего одно действие... и если мы разделим логику на 4 функции, то не сможем избежать дублирования кода остальных, общих действий (нарушим принцип DRY).

Решение через switch - в принципе, самое простое (исключая вариант eval()) и распространенное.

"Лапшу" if..else if лучше не использовать: есть негласное правило, ограничивающее использование такой конструкции тремя вариантами - а у нас их четыре. Да, читаемость не сильно пострадает от еще одного else if, но абсолютно незачем "ползать по краю", когда можно написать код чисто.

Пример с использованием современных возможностей JavaScript:

document.addEventListener('DOMContentLoaded', () => { 
  const [inpA, ops, inpB, btnCalc, inpRes] =  
    Array.from(document.querySelectorAll('.calc > *')); 
  for (let op of ops.children) 
    op.addEventListener('click', selectOp);  
  btnCalc.addEventListener('click', calc);  
 
  function selectOp() { 
    for (let op of this.parentElement.children) 
      op.classList.remove('active');  
    this.classList.add('active');  
  } 
 
  function calc() { 
    let [a, b, result] = [+inpA.value, +inpB.value, 0];  
    if (!isFinite(a) || !isFinite(b)) 
      return inpRes.value = 'Неверный ввод';  
    inpA.value = a;  
    inpB.value = b;  
    const selectedOp = document.querySelector('.calc [data-op].active');  
    switch (selectedOp.dataset.op) { 
      case '+': result = a + b; break;  
      case '-': result = a - b; break;  
      case '∗': result = a * b; break;  
      case '÷': result = a / b;  
    } 
    inpRes.value = result;  
  } 
});
.calc { 
  display: flex; flex-flow: column nowrap;  
  align-items: stretch;  
  max-width: 300px;  
  font: 18px monospace; } 
 
.calc * { font: inherit; outline: none; } 
.calc > * + * { margin-top: 0.5rem; } 
 
.calc div { 
  display: flex; flex-flow: row nowrap;  
  justify-content: space-between;  
  padding: 0 1px; } 
 
.calc [data-op] { width: calc(25% - 8px); } 
 
.calc [data-op]::before,  
.calc button { 
  content: attr(data-op);  
  display: inline-block;  
  width: 100%;  
  font-size: 1.4rem; line-height: 1.4rem;  
  text-align: center;  
  border: none;  
  border-radius: 3px;  
  transition: box-shadow 0.15s linear;  
  box-shadow: 0 0 0 1px #ccc;  
  background: #eee;  
  cursor: pointer; } 
 
.calc [data-op]:hover::before,  
.calc button:hover { box-shadow: 0 0 0 1px #7af; } 
 
.calc [data-op].active::before { background: #aea; } 
 
.calc [readonly] { border: none; text-align: center; }
<div class="calc"> 
  <input type="number"> 
  <div> 
    <span data-op="+" class="active"></span> 
    <span data-op="-"></span> 
    <span data-op="∗"></span> 
    <span data-op="÷"></span> 
  </div> 
  <input type="number"> 
  <button>=</button> 
  <input readonly> 
</div>

Answer 3

Завалялся у меня пример калькулятора, старенький, не до конца написан, но думаю, что логику Вы поймёте и что-то для себя найдёте.

Codepen

class Calculator { 
  constructor(node) { 
    this.node = node; 
 
    if (!this.node) return; 
 
    this.onPanelItemClick = this.onPanelItemClick.bind(this); 
    this.displayOnBoard = this.displayOnBoard.bind(this); 
    this.actionOnNumber = this.actionOnNumber.bind(this); 
 
    this.numbersPanel = this.node.querySelector(".calculator__panel"); 
    this.board = this.node.querySelector(".calculator__window-calculations"); 
    this.answer = this.node.querySelector(".calculator__window-answer"); 
 
    this.numbersPanel.addEventListener("click", this.onPanelItemClick, false); 
  } 
 
  onPanelItemClick(event) { 
    const item = event.target.closest(".calculator__panel-item"); 
 
    if (!item) return; 
 
    if (item.hasAttribute("data-number")) { 
      this.displayOnBoard(item.getAttribute("data-number")); 
    } else { 
      this.actionOnNumber(item.textContent); 
    } 
  } 
 
  displayOnBoard(number) { 
    this.board.textContent += number; 
  } 
 
  actionOnNumber(action) { 
    if (action !== "=" && action !== "c") { 
      this.board.textContent += action; 
    } else if (action === "=") { 
      this.answer.textContent = eval(this.board.textContent); 
    } else if (action === "c") { 
      this.board.textContent = ""; 
    } 
  } 
} 
 
new Calculator(document.querySelector(".calculator"));
* { 
  margin: 0; 
  padding: 0; 
  box-sizing: border-box; 
} 
 
body { 
  font-family: Open sans, sans-serif; 
  background: #e5e5e5; 
} 
 
.container { 
  position: absolute; 
  width: 500px; 
  height: 828px; 
  top: 50%; 
  left: 50%; 
  transform: translate(-50%, -50%); 
} 
 
.calculator__window { 
  padding: 33px 37px; 
  background: #fff; 
  text-align: right; 
  min-height: 180px; 
} 
 
.calculator__window-calculations { 
  font-size: 1.875rem; 
  min-height: 34px; 
} 
 
.calculator__window-answer { 
  font-size: 4.375rem; 
} 
 
.calculator__panel { 
  display: flex; 
  flex-wrap: wrap; 
} 
 
.calculator__panel-item { 
  display: flex; 
  align-items: center; 
  justify-content: center; 
  width: 125px; 
  height: 125px; 
  color: #fff; 
  font-size: 1.563rem; 
  cursor: pointer; 
} 
 
.calculator__panel-item:hover, 
.calculator__panel-item:focus { 
  box-shadow: inset 0px 0px 10px rgba(0, 0, 0, 0.5); 
} 
 
.calculator__panel-item-large { 
  width: 250px; 
} 
 
.calculator__panel-item:first-child { 
  background: #0f266b; 
} 
 
.calculator__panel-item:nth-child(2) { 
  background: #0c2369; 
  display: flex; 
  flex-direction: column; 
} 
 
.calculator__panel-item:nth-child(3) { 
  background: #0c2263; 
} 
 
.calculator__panel-item:nth-child(4) { 
  background: #cf066d; 
} 
 
.calculator__panel-item:nth-child(5) { 
  background: #21479f; 
} 
 
.calculator__panel-item:nth-child(6) { 
  background: #2e54ab; 
} 
 
.calculator__panel-item:nth-child(7) { 
  background: #3f67c4; 
} 
 
.calculator__panel-item:nth-child(8) { 
  background: #d62480; 
} 
 
.calculator__panel-item:nth-child(9) { 
  background: #2e54ab; 
} 
 
.calculator__panel-item:nth-child(10) { 
  background: #3b5fb3; 
} 
 
.calculator__panel-item:nth-child(11) { 
  background: #4d6fbf; 
} 
 
.calculator__panel-item:nth-child(12) { 
  background: #d63a8a; 
} 
 
.calculator__panel-item:nth-child(13) { 
  background: #3f67c4; 
} 
 
.calculator__panel-item:nth-child(14) { 
  background: #4b71c9; 
} 
 
.calculator__panel-item:nth-child(15) { 
  background: #5579cf; 
} 
 
.calculator__panel-item:nth-child(16) { 
  background: #d94e95; 
} 
 
.calculator__panel-item:nth-child(17) { 
  background: #577bcf; 
} 
 
.calculator__panel-item:nth-child(18) { 
  background: #6489de; 
} 
 
.calculator__panel-item:last-child { 
  background: #de64a2; 
}
<div class="container"> 
  <div class="calculator"> 
    <div class="calculator__window"> 
      <div class="calculator__window-calculations"></div> 
 
      <div class="calculator__window-answer"></div> 
    </div> 
 
    <div class="calculator__panel"> 
      <div class="calculator__panel-item" data-type="delete">c</div> 
      <div class="calculator__panel-item"> 
        <span>+</span> 
        <span>-</span> 
      </div> 
      <div class="calculator__panel-item" data-type="remainder">%</div> 
      <div class="calculator__panel-item" data-type="division">/</div> 
      <div class="calculator__panel-item" data-number="7">7</div> 
      <div class="calculator__panel-item" data-number="8">8</div> 
      <div class="calculator__panel-item" data-number="9">9</div> 
      <div class="calculator__panel-item" data-type="multiplication">*</div> 
      <div class="calculator__panel-item" data-number="4">4</div> 
      <div class="calculator__panel-item" data-number="5">5</div> 
      <div class="calculator__panel-item" data-number="6">6</div> 
      <div class="calculator__panel-item" data-type="subtraction">-</div> 
      <div class="calculator__panel-item" data-number="1">1</div> 
      <div class="calculator__panel-item" data-number="2">2</div> 
      <div class="calculator__panel-item" data-number="3">3</div> 
      <div class="calculator__panel-item" data-type="addition">+</div> 
      <div class="calculator__panel-item calculator__panel-item-large" data-number="0">0</div> 
      <div class="calculator__panel-item" data-type="dot">.</div> 
      <div class="calculator__panel-item" data-type="equally">=</div> 
    </div> 
  </div> 
</div>

Answer 4

Можно сделать чуточку красивее и проще. Код не мой, но я его рассматривал, когда начинал изучать js.

   <head> 
    <meta charset="utf-8" />
    <title>Калькулятор</title>
    <style type="text/css">
        #calculator * {font-size: 16px;}
        #calculator table {border: solid 3px silver; border-spacing: 3px; background-color: #EEE; }
        #calculator table td {border-spacing: 3px;}
        input.display {width: 166px; text-align: right;}
        td.buttons {border-top: solid 1px silver;}  
        input[type= button] {width: 40px; height: 30px;}
    </style>
    </head>
    <body>
    <form name="calc" id="calculator">
        <table>
        <tr>
        <td>
            <input type="text" name="input" size="16" class="display">
        </td>
        </tr>
        <tr>
        <td class="buttons">
            <input type="button" name="one" value="1" OnClick="calc.input.value += '1'">
            <input type="button" name="two" value="2" OnClick="calc.input.value += '2'">
            <input type="button" name="three" value="3" OnClick="calc.input.value += '3'">
            <input type="button" name="add" value="+" OnClick="calc.input.value += '+'">
            <br>
            <input type="button" name="four" value="4" OnClick="calc.input.value += '4'">
            <input type="button" name="five" value="5" OnClick="calc.input.value += '5'">
            <input type="button" name="six" value="6" OnClick="calc.input.value += '6'">
            <input type="button" name="sub" value="-" OnClick="calc.input.value += '-'">
            <br>
            <input type="button" name="seven" value="7" OnClick="calc.input.value += '7'">
            <input type="button" name="eight" value="8" OnClick="calc.input.value += '8'">
            <input type="button" name="nine" value="9" OnClick="calc.input.value += '9'">
            <input type="button" name="mul" value="x" OnClick="calc.input.value += '*'">
            <br>
            <input type="button" name="clear" value="c" OnClick="calc.input.value = ''">
            <input type="button" name="zero" value="0" OnClick="calc.input.value += '0'">
            <input type="button" name="doit" value="=" OnClick="calc.input.value = eval(calc.input.value)">
            <input type="button" name="div"  value="/" OnClick="calc.input.value += '/'">
        </td>
        </tr>
        </table>
    </form>
    </body>

Я, правда, слабо понимаю какое применение у таких калькуляторов на практике, т.к. во-первых нет проверки вводимых символов (нужно ограничить ввод), нет проверки на ошибки (например, деление на ноль), нет десятичного разделителя.

READ ALSO
Как авторизоваться в MongoDB, используя MongoClient?

Как авторизоваться в MongoDB, используя MongoClient?

Решил защитить свою бд и подключить аутентификацию для удалённого доступаНо не смог найти информацию об аутентификации через MongoClient, только...

141
Не отправляется форма в telegram из JavaScript

Не отправляется форма в telegram из JavaScript

Хочу отправить форму в телеграм прямо из js файлаВо всем этом новичок

147
Как избежать двойного пролистывания в fullpage.js и ошибок в нем?

Как избежать двойного пролистывания в fullpage.js и ошибок в нем?

Подскажите, на сайте установлен fullpagejs для постраничного скролла

142
Как загрузить изображение в VK

Как загрузить изображение в VK

Есть ссылка на изображение, хочу получить его и загрузить в вк для отправкиТекущий код:

123