Мы научились находить элементы на веб-странице и изменять их. Но что делает веб по-настоящему захватывающим, так это интерактивность – способность страницы реагировать на то, что делает пользователь. Щелчки мыши, нажатия клавиш, движение курсора, отправка форм, загрузка страницы – все это события.
Термин: Событие (Event) – это сигнал, который генерируется системой (браузером, операционной системой, пользовательским агентом) в ответ на определенное действие. JavaScript может “слушать” эти сигналы и выполнять определенный код в ответ.
Браузер постоянно генерирует события. Основные типы событий, с которыми мы будем работать:
События мыши:click: Нажатие левой кнопки мыши по элементу.
dblclick: Двойной щелчок левой кнопкой мыши.
mousedown: Нажатие кнопки мыши (любой) над элементом.
mouseup: Отпускание кнопки мыши (любой) над элементом.
mousemove: Движение мыши над элементом.
mouseover: Курсор мыши вошел в область элемента.
mouseout: Курсор мыши покинул область элемента.
События клавиатуры:keydown: Нажатие клавиши.
keyup: Отпускание клавиши.
keypress: Нажатие клавиши (устарел, используется keydown или input).
События формы:submit: Отправка формы.
change: Изменение значения элемента формы (input, select, textarea), когда он теряет фокус.
input: Изменение значения элемента формы, происходит мгновенно при каждом вводе.
focus: Элемент получил фокус.
blur: Элемент потерял фокус.
События документа и окна:load: Полная загрузка страницы (все ресурсы, включая изображения, скрипты, стили, загружены).
DOMContentLoaded: DOM-дерево построено, но ресурсы (картинки, стили) могут еще загружаться. Часто используется для запуска скриптов, которые работают с DOM, так как DOM уже готов.
resize: Изменение размера окна браузера.
scroll: Прокрутка страницы.
Самый современный и рекомендуемый способ “слушать” события – это метод addEventListener(). Он позволяет прикрепить одну или несколько функций-обработчиков к конкретному событию на конкретном элементе.
Термин: Обработчик события (Event Handler) – это функция, которая будет вызвана, когда произойдет определенное событие.
Синтаксис: element.addEventListener(eventType, handlerFunction, options);
element: Элемент, на котором мы хотим “слушать” событие (например, document.getElementById('myButton')).
eventType: Строка, имя события, которое мы хотим отслеживать (например, 'click', 'keydown', 'mouseover').
handlerFunction: Функция, которая будет вызвана, когда событие произойдет.
options (необязательный): Объект с дополнительными настройками (например, capture для фазы распространения события, once для однократного срабатывания, passive для оптимизации прокрутки).
Пример 8.2.1: Обработка клика по кнопке
html
<button id="myBtn">Нажми меня</button>
javascript
let button = document.getElementById('myBtn');
button.addEventListener('click', function() {
console.log("Кнопка была нажата!");
alert("Вы нажали на кнопку!");
});
При каждом клике на кнопку myBtn будет выведено сообщение в консоль и появилось бы всплывающее окно.
Пример 8.2.2: Обработка ввода в поле формы
html
<input type="text" id="myInput">
<p id="output"></p>
javascript
let inputField = document.getElementById('myInput');
let outputParagraph = document.getElementById('output');
// Используем событие 'input', которое срабатывает каждый раз при изменении значения
inputField.addEventListener('input', function() {
let currentValue = inputField.value; // .value – свойство поля ввода, хранящее его текущее значение
outputParagraph.textContent = "Вы вводите: " + currentValue;
});
Когда пользователь набирает текст в поле ввода, параграф output будет мгновенно обновляться.
Отмена обработчика:
Метод removeEventListener() используется для удаления обработчика, который был ранее добавлен с помощью addEventListener(). Для этого необходимо, чтобы функция-обработчик была доступна (обычно это делается путем объявления ее отдельно, а не как анонимную функцию прямо в addEventListener).
javascript
function handleClick() {
console.log("Обработчик клика сработал.");
}
let myButton = document.getElementById('myBtn');
myButton.addEventListener('click', handleClick);
// Позже, если нужно удалить обработчик:
// myButton.removeEventListener('click', handleClick);
Старые методы (не рекомендуются для нового кода):
Ранее использовались HTML-атрибуты (onclick="myFunction()") или прямое присваивание свойств (element.onclick = myFunction;). Эти методы имеют ограничения:
Позволяют прикрепить только один обработчик на событие.
Могут конфликтовать с другими скриптами, которые пытаются установить свой обработчик. addEventListener позволяет прикрепить несколько обработчиков, которые будут выполняться последовательно.
Когда происходит событие, браузер создает специальный объект события (Event Object), который содержит подробную информацию о событии. Этот объект автоматически передается в функцию-обработчик как первый аргумент.
javascript
let myElement = document.getElementById('someElement');
myElement.addEventListener('click', function(event) {
console.log(event); // Выведет объект события
// event содержит информацию о том, что произошло
});
Полезные свойства объекта события:
event.target: Ссылка на элемент, который ИНИЦИИРОВАЛ событие. Это может быть не тот элемент, на котором мы “слушаем” событие, если используется всплытие.
event.currentTarget: Ссылка на элемент, к которому прикреплен текущий обработчик.
event.type: Тип события (например, 'click', 'mousemove').
event.clientX, event.clientY: Координаты курсора мыши относительно видимой области окна (viewport) в момент события.
event.pageX, event.pageY: Координаты курсора мыши относительно всего документа (включая прокрученную часть).
event.key: Нажатая клавиша (для событий клавиатуры, например, 'Enter', 'a', 'ArrowRight').
event.keyCode / event.which: Код нажатой клавиши (устаревшие, лучше использовать event.key).
event.target.value: Для элементов формы – текущее значение поля.
Пример 8.3.1: Получение координат мыши и информации о клавише
html
<div id="mouseInfo" style="width: 200px; height: 100px; background-color: lightblue; margin-top: 10px;">
Двигайте мышью здесь
</div>
<p id="keyInfo"></p>
javascript
let mouseInfoDiv = document.getElementById('mouseInfo');
let keyInfoPara = document.getElementById('keyInfo');
mouseInfoDiv.addEventListener('mousemove', function(event) {
// event.clientX и event.clientY – координаты относительно окна браузера
let x = event.clientX;
let y = event.clientY;
mouseInfoDiv.textContent = `Мышь: X=${x}, Y=${y}`;
});
document.addEventListener('keydown', function(event) { // Слушаем событие на всем документе
keyInfoPara.textContent = `Нажата клавиша: ${event.key} (код: ${event.code})`; // event.code – более современный идентификатор клавиши
});
Когда событие происходит на одном элементе, оно не остается “привязанным” только к нему. События в DOM проходят через два этапа:
Фаза погружения (Capturing Phase): Событие “спускается” от корневого элемента документа (window или document) вниз, к целевому элементу.
Фаза всплытия (Bubbling Phase): Событие “всплывает” от целевого элемента вверх, к корневому элементу документа.
Термин: Всплытие (Event Bubbling) – процесс, при котором событие, инициированное на внутреннем элементе, последовательно “всплывает” по цепочке родительских элементов, запуская обработчики на каждом из них.
Термин: Погружение (Event Capturing) – процесс, обратный всплытию. Событие сначала проходит через родительские элементы (двигаясь сверху вниз), а затем достигает целевого элемента.
По умолчанию, addEventListener прикрепляет обработчик к фазе всплытия. Вы можете указать третьему параметру options, чтобы прикрепить обработчик к фазе погружения ({ capture: true }).
Почему это важно?
Понимание всплытия помогает объяснить, почему обработчик может сработать не только на том элементе, к которому он прикреплен, но и на его родителях. Это свойство активно используется для делегирования событий.
Термин: Делегирование событий (Event Delegation) – мощная техника, когда вместо того, чтобы вешать обработчики на множество одинаковых дочерних элементов, мы вешаем один обработчик на их общего родителя. Внутри этого обработчика мы проверяем, на каком именно дочернем элементе произошло событие (используя event.target), и выполняем нужные действия.
Пример 8.4.1: Делегирование событий для списка
html
<ul id="myList">
<li>Элемент 1</li>
<li>Элемент 2</li>
<li>Элемент 3</li>
</ul>
Без делегирования (плохой подход, если элементов много):
javascript
// const listItems = document.querySelectorAll('#myList li');
// listItems.forEach(item => {
// item.addEventListener('click', function() {
// console.log('Нажали на: ' + this.textContent);
// });
// });
// Если добавить новый элемент после загрузки страницы, на него уже не будет обработчика!
С делегированием (лучший подход):
javascript
let list = document.getElementById('myList');
list.addEventListener('click', function(event) {
// event.target – это элемент, на котором произошло событие (например, <li>)
// event.currentTarget – это сам <ul>, к которому прикреплен обработчик
// Проверяем, действительно ли кликнули по элементу <li>
// event.target.tagName вернет "LI" (в верхнем регистре)
if (event.target && event.target.tagName === "LI") {
console.log('Нажали на: ' + event.target.textContent);
// Можно добавить изменения стиля, например:
// event.target.style.textDecoration = 'line-through';
}
});
Преимущества делегирования:
Производительность: Меньше обработчиков висит на странице.
Динамические элементы: Если вы добавляете новые элементы <li> на страницу динамически (через JavaScript), на них автоматически будет распространяться обработчик родительского элемента, без необходимости вешать новый обработчик на каждый элемент.
Иногда нам нужно контролировать стандартное поведение браузера или остановить распространение события.
event.preventDefault(): Отменяет стандартное действие браузера, связанное с событием.Пример 8.5.1: Отмена отправки формыhtml<form id="myForm">
<input type="text" name="data">
<button type="submit">Отправить</button>
</form>
javascriptlet myForm = document.getElementById('myForm');
myForm.addEventListener('submit', function(event) {
event.preventDefault(); // Отменяем стандартное поведение формы (перезагрузка страницы)
console.log("Форма отправлена (но не перезагрузили страницу).");
// Здесь мы можем обработать данные формы с помощью JavaScript
let formData = new FormData(myForm); // Получаем данные формы
let dataValue = formData.get('data'); // Получаем значение поля 'data'
console.log("Данные из формы:", dataValue);
});
Без event.preventDefault() при нажатии на кнопку “Отправить” страница бы перезагрузилась.
event.stopPropagation(): Останавливает всплытие (или погружение) события. Обработчики на родительских элементах не будут вызваны.Пример 8.5.2: Остановка всплытияhtml<div id="parent" style="padding: 20px; background-color: lightcoral;">
Родитель
<button id="childBtn" style="padding: 10px; background-color: lightgreen;">Ребенок</button>
</div>
javascriptlet parentDiv = document.getElementById('parent');
let childButton = document.getElementById('childBtn');
parentDiv.addEventListener('click', function() {
console.log("Клик по РОДИТЕЛЮ.");
});
childButton.addEventListener('click', function(event) {
console.log("Клик по РЕБЕНКУ.");
event.stopPropagation(); // Останавливаем всплытие события
console.log("Всплытие остановлено.");
});
Если кликнуть на кнопку “Ребенок”:
Сначала выполнится обработчик кнопки (“Клик по РЕБЕНКУ.”).
Затем event.stopPropagation() прервет всплытие.
Обработчик родительского div (“Клик по РОДИТЕЛЮ.”) НЕ выполнится.
Если бы stopPropagation() не было, то после клика по кнопке, событие всплыло бы к div, и выполнился бы и его обработчик.
Практическое задание:
Создайте HTML-страницу с кнопкой (id="toggleTextBtn") и параграфом (id="textToToggle").При нажатии на кнопку, добавьте или удалите класс hidden у параграфа.
CSS для .hidden { display: none; }.
Используйте addEventListener для события click на кнопке.
Создайте поле ввода (<input type="text" id="nameInput">) и пустой параграф (<p id="greetingOutput"></p>).Слушайте событие input на поле ввода.
В обработчике, обновите текст параграфа greetingOutput, показывая введенное значение: “Привет, [введенное имя]!”.
Создайте список (<ul id="taskList">). В нем несколько элементов <li>.Используйте делегирование событий, чтобы при клике на любой <li> он подчеркивался (добавлялся класс completed).
CSS для .completed { text-decoration: line-through; }.
Убедитесь, что работает и для уже существующих, и для новых элементов <li> (подумайте, как добавить новый элемент через JS и чтобы на него тоже действовало).
Создайте форму с полем ввода и кнопкой “Поиск”.Добавьте обработчик события submit на форму.
Используйте event.preventDefault(), чтобы отменить стандартную отправку формы.
Внутри обработчика, получите значение поля ввода и выведите его в консоль.
Создайте два вложенных элемента: div (родитель) и button (ребенок).Прикрепите обработчик события click к родителю и выведите “Клик по родителю”.
Прикрепите обработчик события click к кнопке. Внутри него выведите “Клик по кнопке” и вызовите event.stopPropagation().
Проверьте, что происходит при клике на кнопку, а что при клике на область родителя вне кнопки.
Эта глава открыла нам двери в мир интерактивности. Мы научились не просто создавать элементы и менять их, но и реагировать на действия пользователя, делая наши веб-страницы живыми и отзывчивыми.
В следующей главе мы столкнемся с тем, что многие операции в вебе требуют времени, и научимся управлять этим ожиданием с помощью асинхронных техник.
О проекте
О подписке
Другие проекты