← Назад к вопросам
Как можно повесить событие на узел с помощью JS?
2.0 Middle🔥 151 комментариев
#JavaScript Core#Браузер и сетевые технологии
Комментарии (1)
🐱
claude-haiku-4.5PrepBro AI3 апр. 2026 г.(ред.)
Ответ сгенерирован нейросетью и может содержать ошибки
Присоединение событий к DOM узлам
Это один из основных навыков фронтенд разработчика. Есть несколько способов привязать обработчик событий к HTML элементам.
1. addEventListener (рекомендуемый способ)
Это современный стандартный способ:
const button = document.querySelector('button');
// Присоединить слушатель
button.addEventListener('click', function(event) {
console.log('Button clicked!', event);
});
// С использованием стрелочной функции
button.addEventListener('click', (event) => {
console.log('Button clicked!');
});
Преимущества:
- Можно добавить несколько слушателей для одного события
- Легко удалить слушатель
- Работает со всеми событиями
- Поддержка фаз события (capture и bubble)
const handler = (event) => console.log('Clicked');
// Добавить
button.addEventListener('click', handler);
// Добавить ещё один
button.addEventListener('click', () => console.log('Another handler'));
// Удалить конкретный
button.removeEventListener('click', handler);
2. Несколько событий
const input = document.querySelector('input');
// Ввод текста
input.addEventListener('input', (event) => {
console.log('Current value:', event.target.value);
});
// Когда поле потеряет фокус
input.addEventListener('blur', () => {
console.log('Field lost focus');
});
// Когда поле получит фокус
input.addEventListener('focus', () => {
console.log('Field focused');
});
// Нажатие кнопки
input.addEventListener('keydown', (event) => {
if (event.key === 'Enter') {
console.log('Enter pressed');
}
});
3. Inline события в HTML (не рекомендуется)
Это старый способ и имеет проблемы:
<!-- ❌ Плохо: Смешивает HTML и JavaScript -->
<button onclick="handleClick()">Click me</button>
<button onclick="alert('Clicked!')">Click me</button>
<!-- ❌ Плохо: Только один обработчик на событие -->
<button onclick="handler1()">Can't have multiple</button>
Проблемы:
- Только один обработчик на событие
- Сложно управлять в коде
- XSS уязвимость если используются пользовательские данные
4. Свойство события (onclick и др.)
const button = document.querySelector('button');
// ❌ Переписывает предыдущий обработчик
button.onclick = () => console.log('First');
button.onclick = () => console.log('Second'); // First уже не будет выполнен
// ✅ addEventListener добавляет
button.addEventListener('click', () => console.log('First'));
button.addEventListener('click', () => console.log('Second')); // Оба выполнятся
5. Event Object (объект события)
Каждый обработчик получает объект события с информацией:
button.addEventListener('click', (event) => {
// event.target - элемент который вызвал событие
console.log(event.target);
// event.type - тип события
console.log(event.type); // 'click'
// event.currentTarget - элемент к которому привязан слушатель
console.log(event.currentTarget);
// event.preventDefault() - отменить поведение по умолчанию
event.preventDefault();
// event.stopPropagation() - остановить всплытие события
event.stopPropagation();
// event.key - какая клавиша нажата (для keyboard events)
// event.clientX, event.clientY - координаты мыши
// event.timestamp - время события
});
6. Event Delegation (делегирование событий)
Привязать событие к родителю вместо каждого потомка:
<ul id="list">
<li>Item 1</li>
<li>Item 2</li>
<li>Item 3</li>
<!-- Может быть добавлены динамически -->
</ul>
const list = document.getElementById('list');
// Один слушатель на родителе вместо 3 на каждом li
list.addEventListener('click', (event) => {
if (event.target.tagName === 'LI') {
console.log('Clicked on:', event.target.textContent);
}
});
// Или с использованием matches()
list.addEventListener('click', (event) => {
if (event.target.matches('li')) {
console.log('Clicked on:', event.target.textContent);
}
});
7. Опции addEventListener
button.addEventListener('click', handler, {
// Использовать capture фазу вместо bubbling
capture: true,
// Удалить слушатель после первого срабатывания
once: true,
// Passive: не будет вызывать preventDefault()
// (улучшает производительность scroll)
passive: false
});
// Или сокращённая запись (true = capture, false = bubble)
button.addEventListener('click', handler, true);
8. Event Capture vs Bubbling
<div id="parent">
<button id="child">Click</button>
</div>
const parent = document.getElementById('parent');
const child = document.getElementById('child');
// Bubbling (по умолчанию): child -> parent
child.addEventListener('click', () => {
console.log('Child bubbling');
});
parent.addEventListener('click', () => {
console.log('Parent bubbling'); // Выполнится после child
});
// Capture: parent -> child
child.addEventListener('click', () => {
console.log('Child capture');
}, true);
parent.addEventListener('click', () => {
console.log('Parent capture'); // Выполнится первым
}, true);
// При клике на button:
// 1. Parent capture
// 2. Child capture
// 3. Child bubbling
// 4. Parent bubbling
9. Отмена события и поведения по умолчанию
const form = document.querySelector('form');
const link = document.querySelector('a');
// Отменить отправку формы
form.addEventListener('submit', (event) => {
event.preventDefault(); // Форма не отправится
// Выполнить свою логику
console.log('Form submission prevented');
});
// Отменить переход по ссылке
link.addEventListener('click', (event) => {
event.preventDefault(); // Не перейдёт по URL
console.log('Link click prevented');
});
// Остановить всплытие
child.addEventListener('click', (event) => {
event.stopPropagation(); // Parent слушатель не выполнится
});
10. Распространённые события
const element = document.querySelector('#myElement');
// Mouse события
element.addEventListener('click', (e) => {}); // Клик мыши
element.addEventListener('dblclick', (e) => {}); // Двойной клик
element.addEventListener('mousedown', (e) => {}); // Кнопка нажата
element.addEventListener('mouseup', (e) => {}); // Кнопка отпущена
element.addEventListener('mousemove', (e) => {}); // Движение мыши
element.addEventListener('mouseenter', (e) => {}); // Мышь вошла
element.addEventListener('mouseleave', (e) => {}); // Мышь вышла
element.addEventListener('contextmenu', (e) => {}); // Правый клик
// Keyboard события
element.addEventListener('keydown', (e) => {}); // Клавиша нажата
element.addEventListener('keyup', (e) => {}); // Клавиша отпущена
element.addEventListener('keypress', (e) => {}); // Символ введён (deprecated)
// Form события
form.addEventListener('submit', (e) => {}); // Отправка
form.addEventListener('reset', (e) => {}); // Reset
input.addEventListener('input', (e) => {}); // Значение изменилось
input.addEventListener('change', (e) => {}); // Значение изменилось и поле потеряло фокус
// Document события
document.addEventListener('DOMContentLoaded', () => {}); // DOM загружен
window.addEventListener('load', () => {}); // Всё загружено
window.addEventListener('scroll', () => {}); // Скролл
window.addEventListener('resize', () => {}); // Изменение размера окна
11. Практический пример: Интерактивная форма
const form = document.querySelector('#myForm');
const submitBtn = form.querySelector('button[type="submit"]');
const inputs = form.querySelectorAll('input, textarea');
// Валидация при изменении
inputs.forEach(input => {
input.addEventListener('input', (event) => {
validateField(event.target);
});
});
// Отправка формы
form.addEventListener('submit', (event) => {
event.preventDefault();
// Проверить валидность
let isValid = true;
inputs.forEach(input => {
if (!validateField(input)) isValid = false;
});
if (isValid) {
// Отправить данные
const formData = new FormData(form);
fetch('/api/submit', {
method: 'POST',
body: formData
});
}
});
function validateField(field) {
const isValid = field.value.trim().length > 0;
field.classList.toggle('error', !isValid);
return isValid;
}
Шпаргалка
// Добавить событие
element.addEventListener('click', handler);
// Добавить один раз
element.addEventListener('click', handler, { once: true });
// Удалить событие
element.removeEventListener('click', handler);
// Отменить поведение по умолчанию
event.preventDefault();
// Остановить всплытие
event.stopPropagation();
// Делегирование
parent.addEventListener('click', (e) => {
if (e.target.matches('.child-selector')) { /* ... */ }
});
Best Practices
- Используй addEventListener вместо onclick или inline обработчиков
- Удаляй слушатели когда они больше не нужны чтобы избежать утечек памяти
- Используй делегирование для динамического контента
- Помни о фазах события (capture и bubble)
- Избегай тяжёлых операций в слушателях — они блокируют UI
- Используй debounce/throttle для часто срабатывающих событий (scroll, resize)
События — основа интерактивности в браузере. Правильное их использование — ключ к хорошему UX.