← Назад к вопросам

Как можно повесить событие на узел с помощью 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

  1. Используй addEventListener вместо onclick или inline обработчиков
  2. Удаляй слушатели когда они больше не нужны чтобы избежать утечек памяти
  3. Используй делегирование для динамического контента
  4. Помни о фазах события (capture и bubble)
  5. Избегай тяжёлых операций в слушателях — они блокируют UI
  6. Используй debounce/throttle для часто срабатывающих событий (scroll, resize)

События — основа интерактивности в браузере. Правильное их использование — ключ к хорошему UX.