14. JS с нуля, ваще с нуля (addEventListener, события, events)

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

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

addEventListener, события, events

Автор конспекта: Иевлев Леонид

Для лучшего усвоения материала данного урока сначала разберём на примерах что такое callback

1. Callback

Callback (функция обратного вызова) — это функция, которую мы передаём в другую функцию как аргумент, чтобы она была вызвана позже, когда это понадобится.

Звучит немного сложно, но на деле всё просто, разберём на простейшем примере: Здесь функция sayHi — выступает в качестве callback, потому что мы передали её в функцию doSomething, и она вызвалась внутри.

script.js
function sayHi() {
  console.log("Hello")
}
 
function doSomething(callback) {
  console.log("Вызвана функция doSomething")
  // вызываем переданную функцию
  callback()
}
// Вызываем функцию doSomething и передаём ей ссылку на функцию sayHi
// которая будет вызвана позже внутри doSomething
doSomething(sayHi)

В результате вызова doSomething(sayHi) в консоль будет выведено 2 сообщения:

  1. Вызвана функция doSomething.
  2. Hello

Важно понимать разницу между вызовом функции и ссылкой на функцию!

sayHi() - это вызов функции так как справа от имени функции стоят круглые скобки (), приводит к немедленному выполнению кода внутри неё.

sayHi - это просто ссылка на функцию, ничего не произойдёт.

Разберём по шагам, что происходит при вызове функции doSomething(sayHi):

  1. В качестве аргумента передаётся ссылка (не путать с вызовом ()) на функцию sayHi.
  2. Выполняется команда: console.log("Вызвана функция doSomething").
  3. Выполняется команда: callback() - происходит вызов функции sayHi() так как мы передали адрес функции sayHi в качестве значения callback
  4. Выполняется команда: console.log("Hello") которая расположена внутри функции sayHi

1.1. Передача callback с аргументом через анонимную функцию.

Чаще всего в качестве callback предаётся функция у которой есть свои аргументы, например:

script.js
function sayHi(name) {
  console.log("Hello: " + name)
}

Передадим функцию sayHi(name) в качестве callback в функцию doSomething, и посмотрим на результат:

script.js
function sayHi(name) {
  console.log("Hello " + name)
}
 
function doSomething(callback) {
  console.log("Вызвана функция doSomething")
  // вызываем переданную функцию
  callback()
}
// Будет выведена ошибка
doSomething(sayHi("Vadim"))

В результате вызова doSomething(sayHi('Vadim')) в консоль будет выведено 3 сообщения:

  1. Hello Vadim
  2. Вызвана функция doSomething
  3. Ошибка: TypeError: callback is not a function

Разберём по шагам, что происходит при вызове функции doSomething(sayHi('Vadim')):

  1. Мы помним что должны передать ссылку на функцию sayHi, но вместо этого мы её вызываем sayHi('Vadim'), что приводит к её немедленному выполнению.
  2. Выполняется команда: console.log("Hello " + name)
  3. Результатом вызова функции sayHi('Vadim') будет значение: undefined (по умолчанию если внутри функции явно не указано возвращаемое значение с помощью ключевого слова return, она возвращает undefined)
  4. Таким образом произойдёт вызов функции doSomething со значением undefined: doSomething(undefined)
  5. Выполняется команда: console.log("Вызвана функция doSomething").
  6. В строке callback() вместо ссылки на функцию будет подставлено значение undefined, по сути будет попытка выполнить команду undefined(), что приведёт к возникновению ошибки: TypeError: callback is not a function

Для решения данной проблемы используется так называемые функции-обёртки.

Функция-обёртка — это функция, которая сама ничего напрямую не делает, а лишь перенаправляет вызов к другой функции (или добавляет дополнительную логику перед/после вызова).

1.2. Использование именованной функции-обёртки

script.js
function sayHi(name) {
  console.log("Hello " + name)
}
// Функция-обёртка
function wrapper() {
  sayHi("Vadim")
}
 
function doSomething(callback) {
  console.log("Вызвана функция doSomething")
  // вызываем переданную функцию
  callback()
}
// Передаётся ссылка на функцию-обёртку которая вызовет sayHi('Vadim')
doSomething(wrapper)

1.2. Использование анонимной функции-обёртки

script.js
function sayHi(name) {
  console.log("Hello " + name)
}
 
function doSomething(callback) {
  console.log("Вызвана функция doSomething")
  // вызываем переданную функцию
  callback()
}
 
doSomething(() => sayHi("Vadim"))
🔗

При создании анонимной функции-обёртки был использован синтаксис стрелочной функции: ( ) => expression.

Рекомендуется изучить синтаксис стрелочных функций так как они будут часто встречаться. Стрелочные функции

2. События

Событие в браузере — это сигнал о том, что в окне или на странице произошло определённое действие. Чаще всего события связаны с взаимодействием пользователя с веб-страницей: например, клик мышью, нажатие клавиши и т.п.

Мы рассматриваем события как механизм реакции на действия пользователя или изменения на веб-странице.

Существует огромное множество типов событий. Важно знать основные и уметь находить остальные.

2.1. События мыши

  • click — клик по элементу (самое частое)
  • dblclick — двойной клик
  • mousedown / mouseup — нажали / отпустили кнопку мыши
  • mousemove — движение мыши
  • mouseover / mouseout — наведение / уход курсора
  • contextmenu — клик правой кнопкой (открытие контекстного меню)

2.2. События клавиатуры

  • keydown — нажата клавиша
  • keyup — отпущена клавиша

2.3. События формы и ввода

  • input — пользователь что-то ввёл
  • change — изменение значения (например, выбрали новый пункт в <select>)
  • submit — отправка формы
  • focus / blur — элемент получил / потерял фокус

3. Метод addEventListener

Метод addEventListener являтся основным методом для работы с событиями в JavaScript. Он позволяет "привязать" функцию-слушатель (listener) к определенному событию на HTML-элементе.

element.addEventListener (eventType, listener)

  • element - элемент на котором мы хотим отслеживать то или иное событие.
  • eventType - тип отслеживаемого события в виде строки (например: 'click')
  • listener - ссылка на функцию которая передаётся в качестве callback (вспоминаем sayHi() из раздела выше), и которая будет вызвана когда произойдёт событие.

3.1. Шаги для подписки на событие

  1. Найти HTML-элемент: сначала необходимо получить ссылку на элемент, на котором мы хотим отслеживать событие.
  2. Вызвать addEventListener(): У найденного элемента вызывается метод addEventListener().
  3. Передать аргументы: Метод addEventListener() принимает два основных аргумента:
  • Тип события (строка): Например, 'click', 'keydown', 'keyup'.
  • Функция-слушатель (listener function): Это ссылка на функцию, которая будет выполнена, когда произойдет указанное событие.

3.2. Пример использования addEventListener

index.html
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Document</title>
    <link rel="stylesheet" href="./CSS/style.css" />
  </head>
 
  <body>
    // Элемент 'кнопка' на которой будем отслеживать события
    <button id="my-button">Button</button>
    // Элемент 'текст' в котором будет отображаться результат (для наглядности)
    <input id="my-input" type="text" />
    // Подключаем наш JavaScript-файл
    <script src="./script.js"></script>
  </body>
</html>
script.js
function sayHi(name) {
  myInput.value = "Hello " + name
}
 
function mouseOver() {
  myInput.value = "mouseover"
}
 
function mouseOut() {
  myInput.value = "mouseout"
}
 
// Получаем элемент button c id='my-button'
const myButton = document.getElementById("my-button")
 
// Получаем элемент input c id='my-input'
const myInput = document.getElementById("my-input")
 
// Добвляем обратчик собития на клик мышкой, с ипользование стрелочной функции
myButton.addEventListener("click", () => sayHi("Vadim"))
// Добвляем обратчик события на наведение курсора мышки на элемент
myButton.addEventListener("mouseover", mouseOver)
// Добвляем обратчик события на то: когда курсор мыши покидает границы элемента
myButton.addEventListener("mouseout", mouseOut)
🔗

Более подробно о том как работают события в браузере вы можете ознакомится перейдя на ресурс: learn.javascript.ru

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

Задача 1

Поле ввода пароля

У нас есть поле ввода пароля. Вводятся “звёздочки” вместо текста. Это делается с помощью тега input с атрибутом type='password'.

Рядом есть кнопка: показать пароль.

При нажатии на кнопку пароль должен отображаться как простой текст. При повторном нажатии — снова звёздочками. (подсказка: при клике нужно менять type с password на text). Используем if-else.

https://jsfiddle.net//s0zybm6t/

Задача 1.2

Поле ввода пароля

У нас есть поле ввода пароля. Вводятся “звёздочки” вместо текста. Это делается с помощью тега input с атрибутом type='password'.

Рядом есть кнопка: показать пароль.

Тоже самое, что и в предыдущем занятии, но пароль должен показываться при нажатии на кнопку (не клике, а именно нажатии — событие mousedown). А при отпускании мыши буквы должны снова превращаться в звёздочки (событие mouseup).

Задача 2:

Изменение статуса в ВК

Изначально видим текст (тег span).

status-1

Кликаем по тексту (спану) — спан исчезает и появляется input с тем же текстом и кнопка СОХРАНИТЬ.

status-2

Вводим новый текстовый статус, кликаем кнопку СОХРАНИТЬ…

Видим снова спан с новым текстом. Кнопка и инпут исчезают.

Задача 3

Меняем местами значения

Есть 2 инпута. Вводим в них любые тексты. Внизу кнопка.

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

https://jsfiddle.net/kuzyuberdin/9wmz86ar/

Задача 4

Подсветка ошибки ввода

Есть 10 текстовых полей. Вы вводите туда числа. Если число выходит за пределы диапазона 10–50, то поля должны выделяться красной рамкой (красным бордером).

При вводе корректного числа — рамка должна исчезать.

https://jsfiddle.net/y34f7j0f/

Задача 5

Есть 5 картинок. Они маленькие (thumbnails), чтобы не жрать трафик. А внизу невидимая картинка — пока что пустая (без src).

Кликаем по маленьким картинкам, и выбранная отображается в большой картинке снизу — как в галерее.

Важный момент: большая картинка или маленькая — это два разных файла (разные разрешения), а не растягивание/сжатие.

https://jsfiddle.net/kuzyuberdin/o6rxdb8w/

Задача 6:

Боковое выезжающее меню

При клике на гамбургер вылазит боковое меню.

Исходное состояние: https://jsfiddle.net/kuzyuberdin/vxapnL4g/10/

Подсказка: меню «уехало» влево из-за стилей в CSS — изучите внимательно. Если меню добавить класс active, меню покажется.

Задача 7

Боковое выезжающее меню, CSS-доработка

  • Гамбургер должен поворачиваться (transform) на 90 градусов и обратно.
  • Меню должно выезжать/уезжать медленно (transition).

Задача 8

Боковое выезжающее меню, иной подход

Когда нужно показать меню — добавляем самому меню класс active. Нужно повернуть кнопку — ей тоже добавляем класс.

Сделаем иначе: вся страница обёрнута в div с классом entire-page. Добавляем/удаляем класс active ей, а дочерние элементы (меню и кнопка) реагируют через вложенные CSS-селекторы.

Видео: https://www.youtube.com/watch?v=uB4ecTXEp4k

Задача 9

Toggle подменю

При клике на заголовок span меню (language или cities) соответствующее подменю должно раскрываться; повторный клик — сворачивает.

Исходное состояние: https://jsfiddle.net/kuzyuberdin/eod41n04/125/

Подсказка: сначала вручную: удалите класс show у li.main-menu-item, добавьте его другой li. Поймите, почему подменю показывается/прячется — изучите CSS. Затем автоматизируйте кликами. Полезно: e.currentTarget.parentElement или e.currentTarget.closest('.main-menu-item').

Задача 10

Гармошка

Как и в прошлом задании, но при открывании одного подменю — ранее открытое должно закрываться.

Пример: https://jqueryui.com/accordion/#default

Исходное состояние: https://jsfiddle.net/kuzyuberdin/eod41n04/125/

Задача 11

Контекстное меню

При клике правой кнопкой мыши в точке клика должна появиться менюшка.

https://jsfiddle.net/kuzyuberdin/carL6d03/43/

  1. Кликните в любом месте правой кнопкой мыши — появляется слева вверху менюшка.
  2. Кликните левой кнопкой по тексту — меню исчезает.
  3. Изучите написанный код.
  4. Закомментируйте preventDefault и протестируйте. Что изменилось? Почитайте про preventDefault.
  5. Допишите логику, чтобы меню появлялось в месте клика правой кнопкой мыши. Подсказка: в объекте события e есть координаты клика. Присвойте их menu.style.left и menu.style.top.

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

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