15.JS с нуля, ваще с нуля (Калькулятор, HTML+CSS+JS)

Оценить качество материала и подачу материала автором видео:

Front-end

Трудоустройтесь middle front-end разработчиком на React JS (TypeScript) за 12-16 месяцев обучения с ежедневной менторской поддержкой в формате видео 1 на 1 и коммерческими проектами в портфолио

Перейти на курс
Front-end

Back-end

Трудоустройтесь middle back-end разработчиком за 12-16 месяцев обучения с ежедневной менторской поддержкой в формате видео 1 на 1 и коммерческими проектами в портфолио

Перейти на курс
Back-end

Карьерный бустер

Получите коммерческий опыт на реальных стартапах, прокачайте tech & soft навыки, научитесь работать в команде, проходить собеседования и получите первую работу в IT!

Перейти на курс
Карьерный бустер

Основы Front-end

Сделайте первый шаг в IT, освоив базовые знания разработки и научившись создавать небольшие проекты на JavaScript

Перейти на курс
Основы Front-end

Основы Back-end

Сделайте первый шаг в IT, освоив базовые знания разработки. Без опыта. Без математики. Только практика: JavaScript, SQL, Node JS, база данных

Перейти на курс
Основы Back-end

Калькулятор, HTML+CSS+JS

Автор конспекта: Стогниева Виктория

1.Основная тема урока: События (Events) 🎯

Почему это важно?

  • События — фундаментальная концепция для создания интерактивных веб-приложений
  • Позволяют реагировать на действия пользователя (клики, ввод текста и др.)
  • Превращают статические HTML-страницы в динамические интерфейсы

Без понимания событий невозможно создание современного фронтенда

2. Рекомендуемый подход к разработке 🏗️

Начинайте с вёрстки (HTML + CSS):

html
<div class="jskmb-calculator">
  <div class="operations-block">
    <button id="buttonPlus">+</button>
    <button id="buttonMinus">-</button>
    <button id="buttonMultiply">*</button>
    <button id="buttonDivide">/</button>
  </div>
  <div class="separator">
    <hr />
  </div>
  <div class="inputs-block">
    <div class="input-block">
      <label>Number 1</label>
      <input type="number" id="number1" />
    </div>
    <div class="input-block">
      <label>Number 2</label>
      <input type="number" id="number2" />
    </div>
  </div>
</div>
 
<script src="js/index.js"></script>
<link rel="stylesheet" type="text/css" href="css/index.css" />
css
.jskmb-calculator {
  width: 500px;
  margin: 0 auto;
  text-align: center;
  background-color: aliceblue;
  padding: 20px;
  border: 1px solid black;
}
 
.jskmb-calculator .operations-block button {
  width: 40px;
  height: 40px;
  margin: 20px;
}
 
.jskmb-calculator .inputs-block .input-block {
  display: inline-block;
  padding: 10px;
}
 
.jskmb-calculator .inputs-block .input-block label {
  display: block;
}

3. Проблема конфликтов стилей ⚠️

Конфликты стилей возникают, когда разные CSS-правила с одинаковой специфичностью применяются к одному элементу, что приводит к непредсказуемым результатам. Для предотвращения конфликтов стилей необходимо использовать вложенность селекторов. Вместо того, чтобы применять стили к общим элементам, следует указывать полный путь к элементу в контексте его родительских блоков. Этот подход, известный как использование "селекторов вложенности", делает CSS-правила более специфичными и уменьшает вероятность нежелательного переопределения стилей.

Ключевой принцип: Вложенность селекторов

❌ Плохой подход (риск конфликтов)

css
button {
  background-color: blue;
  color: white;
}
 
label {
  font-weight: bold;
  margin-bottom: 10px;
}

✅ Правильный подход (с вложенностью)

Использование вложенных селекторов позволяет создавать более специфичные и целенаправленные CSS-правила:

css
.js-kmb-calculator .operations-block button {
  background-color: #007bff;
  color: white;
  padding: 10px 20px;
  border: none;
  border-radius: 4px;
}
 
.js-kmb-calculator .input-block label {
  font-weight: 600;
  margin-bottom: 8px;
  display: block;
  color: #333;
}

4. Привязка функций-обработчиков к событиям HTML-элементов в JavaScript

Основной метод: addEventListener()

Для привязки функций-обработчиков к событиям HTML-элементов используется метод addEventListener().

Пошаговый процесс привязки📋

1. Получение ссылки на HTML-элемент

Сначала необходимо получить ссылку на нужный HTML-элемент:

javascript
// Получение элемента по ID
var buttonPlus = document.getElementById("buttonPlus")
var buttonMinus = document.getElementById("buttonMinus")
var buttonMultiply = document.getElementById("buttonMultiply")
var buttonDevide = document.getElementById("buttonDevide")

2. Создание функций-обработчиков

javascript
function onButtonPlusClick() {
  var input1 = document.getElementById("number1")
  var input2 = document.getElementById("number2")
 
  var number1 = Number(input1.value)
  var number2 = Number(input2.value)
 
  var result = number1 + number2
  window.alert(result)
}
 
function onButtonMinusClick() {
  var input1 = document.getElementById("number1")
  var input2 = document.getElementById("number2")
 
  var number1 = Number(input1.value)
  var number2 = Number(input2.value)
 
  var result = number1 - number2
  window.alert(result)
}
 
function onButtonMultiplyClick() {
  var input1 = document.getElementById("number1")
  var input2 = document.getElementById("number2")
 
  var number1 = Number(input1.value)
  var number2 = Number(input2.value)
 
  var result = number1 * number2
  window.alert(result)
}
 
function onButtonDivideClick() {
  var input1 = document.getElementById("number1")
  var input2 = document.getElementById("number2")
 
  var number1 = Number(input1.value)
  var number2 = Number(input2.value)
 
  // Проверка деления на ноль
  if (number2 === 0) {
    window.alert("Ошибка: деление на ноль!")
    return
  }
 
  var result = number1 / number2
  window.alert(result)
}

3. Применение addEventListener()

Затем к элементу применяется метод addEventListener():

javascript
buttonPlus.addEventListener("click", onButtonPlusClick)
buttonMinus.addEventListener("click", onButtonMinusClick)
buttonMultiply.addEventListener("click", onButtonMultiplyClick)
buttonDevide.addEventListener("click", onButtonDevideClick)

4. Правильная передача функции

Правильно: передавать только название функции без скобок

javascript
button.addEventListener("click", onButtonClick) // Верно

Неправильно: передавать функцию со скобками

javascript
button.addEventListener("click", onButtonClick()) // Ошибка!

Почему происходит конкатенация?❓

Значения, полученные из атрибутов HTML-элементов (например, value у input), всегда являются строками, даже если пользователь вводит числа.

Механизм работы оператора +🧩

В JavaScript оператор + ведет себя по-разному в зависимости от типов операндов:

javascript
// Числа + Числа = Математическое сложение
console.log(10 + 20) // Результат: 30
 
// Строки + Строки = Конкатенация (склеивание)
console.log("10" + "20") // Результат: "1020"
 
// Строки + Числа = Конкатенация
console.log("10" + 20) // Результат: "1020"

🏠 Домашнее задание

Калькулятор - подготовка

1. Напишите функцию суммирования чисел

Создайте функцию, которая

  • суммирует 2 числа
  • принимает 2 параметра
  • ретурном (return) возвращает результат во внешний мир

Вот так я (представитель внешнего мира) хочу уметь вызывать эту функцию и не думать, что там у неё внутри:

js
var result = sum(12, 23)
console.log(result) // 35

2. Напишите аналогичные функции для multiply, minus, divide

Все эти 4 функции разместите в отдельном файле math.js, подключите этот файл перед вашим calculator.js, в котором будет логика уже приложения.

А теперь погнали бомбить калькуляторы используя функции из нашей псевдо-библиотеки math.js 🚀

Калькулятор v1

Калькулятор должен иметь 2 поля ввода: по одному для каждого числа, с которыми будет производиться математическая операция.

Жмём на кнопку — в span-е РЕЗУЛЬТАТ видим результат.

Список операций:

  • умножить
  • разделить
  • сложить
  • вычесть

Примерный вид калькулятора:

calc v1

Калькулятор v2

Кнопка Посчитать — одна. Операцию выбираем в select.

calc v2

💡

Если чувствуешь силу в себе и тебе это всё легко, то переходи сразу к Калькулятор v3

Микрозадачка 1

microtask 1

Имеется input (пустой) и 3 кнопки.

  • Кликаем по кнопке 2 → в инпуте видим: 2
  • Кликаем по кнопке 1 → в инпуте видим: 21 (справа дописалась единица)
  • Кликаем опять по кнопке 2 → в инпуте видим: 212 (дописали 2)
  • Кликаем по кнопке 3 → в инпуте видим: 2123

И так далее…

Калькулятор v3

Сделать ввод в поля с помощью кнопок. То есть примерно как в настоящем калькуляторе:

calc v3

Вот так он должен себя вести: пример видео

Инструкции

Первым делом определяемся с алгоритмом.

Вопрос: что происходит, когда мы нажимаем на кнопку? Ответ: какую смотря кнопку.

Вопрос 1: на кнопку с числом

Ответ 1: берём и приплюсовываем (конкатенируем строки) справа цифру, отображающуюся в input.

Было, например: 3434 Нажимаем 8 Получается: 34348

Можно на этом остановиться и начать кодить: рисуем все ЧИСЛОВЫЕ кнопки и вешаем на них один обработчик события (листенер / подписчик / subscriber / handler).

Почему один? Потому что АЛГОРИТМИЧЕСКИ при нажатии на любую кнопку с ЦИФРОЙ происходит одно и то же: мы дописываем справа к input значение кликнутой кнопки.

Примерный код:

js
var numberButtons = document.querySelectorAll(".number")
for (let i = 0; i < numberButtons.length; i++) {
  numberButtons.addEventListener("click", numberButtonClickListener)
}
 
function numberButtonClickListener(e) {
  // вот здесь находим инпут и приписываем к его значению справа значение нажатой кнопки
  // e.currentTarget.value
}

Первый алгоритмический кусок — это содержимое функции numberButtonClickListener.


Вопрос 2: а когда кликаем на равно?

Ответ: рано думать про равно. Нужно идти логически последовательно.

Как работает калькулятор обычный?

  1. вводим число
  2. жмём кнопку операции
  3. вводим второе число
  4. жмём равно, проводим операцию и выполняем результат

Давайте свяжем каждое действие алгоритма с каким-то листенером (ведь в них у нас логика):

  1. вводим число → numberButtonClickListener
  2. жмём кнопку операции → operationButtonClickListener
  3. вводим второе число → numberButtonClickListener
  4. жмём равно → resultButtonClickListener

Логически 3 группы

  1. Нажатие на цифры (при нажатии на любую цифру мы делаем одно и то же, только цифра разная)

  2. Нажатие на кнопки с операцией (при нажатии на любую операцию мы делаем одно и то же — после нажатия на равно производим операцию между двумя числами, просто операции разные)

  3. Нажатие на равно (кнопка в одном экземпляре, действие одно: число1 — ОПЕРАЦИЯ — число2)

Первый пункт реализовали ✅

Второй пункт

Вопрос: что там происходит? Выполняем действие сразу? Нажали на плюс → значит начинаем плюсовать?

Ответ: нет, мы не знаем второго числа. Операцию, которую нажали, мы должны выполнить в будущем, когда кликнем на кнопку =.

Вопрос: мы нажали на кнопку, например +, сейчас. А это значение операции нам понадобится только потом, когда кликнем по =. Как сохранить?

Ответ: в глобальную переменную (зло, но пока что так), например:

js
operation = e.currentTarget.value

Шаг 2 заключается в том, чтобы сохранить значение операции на будущее

Вспомним алгоритм:

  1. вводим число → numberButtonClickListener
  2. жмём кнопку операции → operationButtonClickListener
  3. вводим второе число → numberButtonClickListener
  4. жмём равно → resultButtonClickListener

После нажатия на кнопку операции начинаем вводить второе число.

Но там же введено было первое число? Значит, нужно его очистить!

То есть шаг 2 = два действия:

  • СОХРАНИТЬ ЗНАЧЕНИЕ ОПЕРАЦИИ НА БУДУЩЕЕ
  • ОЧИСТИТЬ ПОЛЕ ВВОДА

Супер, почти работает. Переходим к пункту 4 — нажатие на равно.

Что делаем? Берём первое число, операцию, второе число и получаем результат.

Но… мы вытерли первое число на шаге 2! Значит, нужно перед вытиранием сохранить это значение.

Куда? В глобальную переменную, например firstNumber.

Итого: шаг 2 содержит 3 операции

  1. СОХРАНИТЬ ЗНАЧЕНИЕ ОПЕРАЦИИ НА БУДУЩЕЕ
  2. СОХРАНИТЬ ЧИСЛО1 НА БУДУЩЕЕ
  3. ОЧИСТИТЬ ПОЛЕ ВВОДА

Шаг 4 — кнопка равно

  • Первое число → из переменной firstNumber
  • Второе число → из input
  • Операция → из переменной operation
js
function resultButtonClickListener() {
  var secondNumber = displayInputEl.value;
  var result = 0;
  if (operation === '+') {
      result = firstNumber + secondNumber;
  } else if (operation === "*") {
      result = firstNumber * secondNumber;
  } else if (...)
 
  // в конце записываем ИТОГ в инпут displayInputEl
}

Slider

Закрепляем темы, пытаясь сделать слайдер!

Версия 1

carousel

Кликаем вправо-влево и картинка меняется на следующую или предыдущую.

Какие есть варианты реализации?

  1. Одна базовая картинка (имеет класс show), остальные — скрыты по умолчанию (в CSS прописано правило для картинок):
css
img {
  display: none;
}
img.show {
  display: block;
}
  1. Находим следующую картинку и показываем её, а предыдущую прячем.

Версия 2

У нас всего одна картинка. В JS хранится массив адресов. По кликам NEXT/BACK берём из массива следующий/предыдущий URL и подставляем его в src нашей единственной картинки.

Боевой маршрут (JS Ваще с нуля)

Видеоурок - 16 видео из 29