1. Ошибка: обработчик не срабатывает
Симптомы: Клик по кнопке — ничего не происходит. Вводишь в поле — а в консоли тишина. Жмёшь на ссылку — но обработчик будто в отпуске.
Причины:
Самое частое: обработчик не был правильно навешан. Например, вы пытаетесь найти элемент, которого ещё нет в DOM, или промахнулись с селектором.
// Пример: элемент ещё не создан на момент навешивания обработчика
const btn = document.getElementById('myBtn');
btn.addEventListener('click', function() {
console.log('Кнопка нажата');
});
Если этот код стоит в <head> или до того, как <button id="myBtn"> появился в DOM, btn будет null — и никакой ошибки не будет, просто обработчик не навесится.
Решение:
Навешивайте обработчики после полной загрузки DOM. Например, в конце <body>, или внутри обработчика события DOMContentLoaded:
document.addEventListener('DOMContentLoaded', function() {
const btn = document.getElementById('myBtn');
btn.addEventListener('click', function() {
console.log('Кнопка нажата');
});
});
Ещё одна причина: Опечатка в селекторе или неверный id/класс.
2. Ошибка: обработчик срабатывает слишком много раз
Симптомы: В консоли появляется по 2, 3 или даже 10 сообщений вместо одного. При клике на кнопку что-то происходит несколько раз подряд.
Причины:
Чаще всего: обработчик навешивается в цикле или при каждом действии пользователя, а не один раз.
const btn = document.getElementById('myBtn');
function onClick() {
console.log('Клик!');
}
// Ошибка: обработчик добавляется при каждом клике!
btn.addEventListener('click', function() {
btn.addEventListener('click', onClick);
});
Или: обработчик не снимается после использования, если он должен был быть "одноразовым".
Решение:
Навешивайте обработчик один раз, вне других обработчиков и циклов. Если обработчик нужен только для одного раза — снимайте его вручную:
function onClickOnce(event) {
console.log('Кнопка была нажата!');
event.target.removeEventListener('click', onClickOnce);
}
btn.addEventListener('click', onClickOnce);
3. Ошибка: this внутри обработчика не тот, что ожидался
Симптомы: Внутри обработчика this — не элемент, а undefined или window. Вы хотите изменить стиль кнопки, а в обработчике this не работает.
Причины:
В стандартной функции:
В обработчике, навешанном через addEventListener, this указывает на элемент, на который навешан обработчик.
btn.addEventListener('click', function() {
this.style.background = 'red'; // ок!
});
Но если вы используете стрелочную функцию:
btn.addEventListener('click', () => {
this.style.background = 'red'; // this тут не про кнопку!
});
Стрелочные функции не имеют своего this!
Внутри стрелочной функции this берётся из внешнего контекста (например, из window или из модуля). Поэтому для обработчиков событий лучше использовать обычные function.
Решение:
Используйте обычные функции, если нужен this.
Или используйте event.target:
btn.addEventListener('click', (event) => {
event.target.style.background = 'red';
});
4. Ошибка: обработчик навешивается на коллекцию, а не на элементы
Симптомы: Хотите навесить обработчик на все кнопки, но ничего не работает. В консоли: "addEventListener is not a function".
Причины:
Вы получили коллекцию элементов (NodeList или HTMLCollection), а не отдельный элемент, и пытаетесь навесить обработчик на всю коллекцию.
const buttons = document.getElementsByClassName('myBtn');
buttons.addEventListener('click', handler); // Ошибка!
Решение:
Перебирайте коллекцию и навешивайте обработчик на каждый элемент:
const buttons = document.querySelectorAll('.myBtn');
buttons.forEach((btn) => {
btn.addEventListener('click', handler);
});
5. Ошибка: забыли снять обработчик — утечка памяти
Симптомы: После навигации или удаления элементов обработчики "висят" и продолжают работать. Приложение начинает "тормозить" после долгой работы.
Причины:
Если вы динамически создаёте и удаляете элементы или переходите между страницами (SPA), старые обработчики могут продолжать жить в памяти, если не были сняты.
Решение:
Снимайте обработчики при удалении элементов или перед их повторным созданием.
function handler() {
// ...
}
btn.addEventListener('click', handler);
// ...
btn.removeEventListener('click', handler);
Важно:
removeEventListener работает только если вы передаёте ту же функцию, что и при навешивании! Анонимные функции не снимутся.
6. Ошибка: обработчик срабатывает на родителе, а не на дочернем элементе
Симптомы: Клик по дочернему элементу вызывает обработчик родителя. Нужно обработать клик только по конкретной кнопке, но срабатывает на всём контейнере.
Причины:
Это связано с "всплытием событий" (event bubbling) — событие поднимается вверх по DOM.
Решение:
Проверяйте, на каком элементе произошло событие, с помощью event.target.
container.addEventListener('click', function(event) {
if (event.target.matches('button.special')) {
// Только для кнопок с классом special
doSomething();
}
});
Если нужно остановить всплытие:
event.stopPropagation();
7. Ошибка: забыли event.preventDefault() — стандартное поведение браузера мешает
Симптомы: При сабмите формы страница перезагружается, хотя вы хотели сделать это через JS. Клик по ссылке уводит пользователя на другой адрес, хотя вы хотели обработать клик через JS.
Причины:
Стандартное поведение браузера не отменено.
Решение:
В обработчике вызвать event.preventDefault():
form.addEventListener('submit', function(event) {
event.preventDefault();
// ваша логика отправки формы через JS
});
8. Ошибка: неправильная работа с параметрами обработчика
Симптомы: Обработчик вызывается сам по себе, без события. В консоли ошибка: "Cannot read property 'target' of undefined".
Причины:
Вы случайно вызываете обработчик сразу, а не передаёте функцию.
btn.addEventListener('click', myHandler()); // Ошибка: myHandler вызовется сразу
Решение:
Передавайте саму функцию, а не результат её вызова:
btn.addEventListener('click', myHandler); // правильно
Если нужно передать параметры, используйте обёртку:
btn.addEventListener('click', function(event) {
myHandler(event, 42);
});
9. Ошибка: обработчик не работает после динамического создания элемента
Симптомы: Добавили элемент через JS, но обработчик не срабатывает. Старые элементы работают, новые — нет.
Причины:
Обработчики навешиваются только на существующие в DOM элементы. Если элемент создан после навешивания, обработчик на нём не появится.
Решение:
Навешивайте обработчик сразу после создания элемента:
const btn = document.createElement('button');
btn.textContent = 'Кнопка';
btn.addEventListener('click', handler);
container.appendChild(btn);
Или используйте делегирование событий — навешивайте обработчик на родительский элемент.
10. Ошибка: смешение inline-обработчиков и addEventListener
Симптомы: В HTML: <button onclick="doSomething()">
В JS: button.addEventListener('click', doSomethingElse)
В итоге срабатывают оба обработчика, или только один, или что-то странное.
Причины:
Обработчики, навешанные через HTML (onclick="..."), и через JS (addEventListener) независимы друг от друга. Они могут срабатывать оба, порядок не всегда очевиден.
Решение:
Используйте только один подход! Рекомендуется использовать JS и addEventListener для отделения логики от разметки.
11. Ошибка: неправильное использование removeEventListener
Симптомы: Пытаетесь снять обработчик, но он не снимается. В консоли: обработчик продолжает срабатывать.
Причины:
removeEventListener работает только если вы передаёте ровно ту же функцию, что и при навешивании.
btn.addEventListener('click', function() {
// ...
});
btn.removeEventListener('click', function() {
// ...
}); // Не снимется! Это две разные функции
Решение:
Используйте именованные функции:
function handler() {
// ...
}
btn.addEventListener('click', handler);
btn.removeEventListener('click', handler);
12. Ошибка: забыли про пассивные события при скролле
Симптомы: Скроллинг на мобильных устройствах "тормозит". В консоли предупреждение о том, что обработчик не пассивный.
Причины:
Для событий touchstart, touchmove, wheel рекомендуется явно указывать { passive: true }, если вы не используете event.preventDefault(). Это ускоряет скроллинг.
Решение:
window.addEventListener('scroll', handler, { passive: true });
ПЕРЕЙДИТЕ В ПОЛНУЮ ВЕРСИЮ