Вставив кнопку через AJAX. Навісив на неї .click(). Кнопка не реагує. Погугливши, переніс обробник у callback після AJAX — запрацювало. Але тепер він навішується заново при кожному запиті, і один клік викликає функцію п’ять разів.
Це класична проблема, яку 90% вирішують неправильно. Правильне рішення — один метод. Розберемось, який саме.
Що таке подія в jQuery
Подія — це реакція на дію: клік, скрол, ввід у поле, submit форми, завантаження сторінки. Під капотом jQuery використовує той самий addEventListener, просто додає зверху кросбраузерну нормалізацію, делегування і неймспейси.
У 2006-му це було рятівним колом — attachEvent в IE, addEventListener у всіх інших, різні event.target і event.srcElement. Сьогодні різниці між браузерами майже немає, але синтаксичні зручності jQuery залишились. Розглянемо їх по черзі.
.on() — єдиний метод, який треба знати
Усі інші способи навісити обробник зводяться до .on(). Він вміє чотири важливі речі.
1. Простий обробник:
$('#btn').on('click', function() {
console.log('clicked');
});
2. Делегування — обробник навішується на батьківський елемент і спрацьовує для дочірніх, які відповідають селектору:
$('#list').on('click', '.item', function() {
console.log('clicked item:', this);
});
Це вирішує AJAX-проблему з хука: батьківський #list існує з моменту завантаження, тому обробник навішується один раз і працює для всіх .item, включно з тими, які додаються пізніше.
3. Неймспейси — щоб потім точно знати, який обробник видаляти:
$('#btn').on('click.modal', function() { ... });
$('#btn').on('click.analytics', function() { ... });
4. Кілька подій одним викликом і передача даних:
$('input').on('focus blur', function() { ... });
$('#btn').on('click', { userId: 42 }, function(e) {
console.log(e.data.userId);
});
.off() — як знімати обробники без побічних ефектів
Якщо .on() — рука, то .off() — гумка. Синтаксис дзеркальний.
$('#btn').off('click'); // всі click-обробники
$('#btn').off('click.modal'); // тільки конкретний неймспейс
$('#list').off('click', '.item'); // з делегуванням
$('#btn').off(); // ВСІ обробники — обережно
Останній варіант — найнебезпечніший. Ти видалиш не лише свої обробники, а й ті, що навісили Bootstrap, WooCommerce, інші плагіни. Тому неймспейси в реальних проєктах — не забаганка, а страховка.
.trigger() — програмне запускання події
Коли треба “натиснути” кнопку з коду — submit форми після валідації, ініціалізація галереї, кастомна подія між модулями:
$('#btn').trigger('click');
$('form').trigger('submit');
// Кастомна подія з даними
$(document).trigger('user:login', { id: 42 });
$(document).on('user:login', function(e, data) {
console.log('logged in:', data.id);
});
Кастомні події з двокрапкою у назві — зручний спосіб зв’язати незалежні частини коду без прямих викликів функцій.
Шорткати: .click(), .hover(), .submit(), .focus()
Усі вони — синтаксичний цукор поверх .on(). $('#btn').click(fn) ідентичне $('#btn').on('click', fn). Зручно для одноразових навішувань.
Нюанс: виклик шортката без аргументу запускає подію, а не навішує обробник. $('#btn').click() = $('#btn').trigger('click'). Те саме ім’я з двома різними поведінками — джерело плутанини.
Окремо корисний .hover(enter, leave) — приймає дві функції для mouseenter і mouseleave. Одна стрічка замість двох викликів .on().
Починаючи з jQuery 3.3, шорткати вважаються deprecated — офіційно рекомендують .on(). У реальному коді вони досі всюди, видаляти їх з 15-річного проєкту немає сенсу.
Кладовище: що побачиш у легасі
Ці методи ще живі в старих темах WordPress, статтях на Хабрі і відповідях Stack Overflow 2012-го року. Якщо зустрічаєш — розумієш, на що замінити.
.bind()/.unbind()— deprecated з jQuery 3.0. Замінник:.on()/.off()..live()— видалений у 1.9 (2013 рік). Тобто в сучасному jQuery його просто немає. Замінник:.on()з делегуванням..delegate()/.undelegate()— deprecated з 3.0. Замінник: той самий.on()..toggle(fn, fn)як почерговий обробник — видалений у 1.9. Сучасний.toggle()тільки показує/ховає елемент.
Правило для легасі: не видаляй, якщо не зобов’язаний. Якщо оновлюєш jQuery до 3.x — перевір, що нічого не зламалося, і замінюй при рефакторингу сусідніх ділянок.
jQuery проти addEventListener у 2026
Нативний API для подій уже майже не поступається jQuery:
document.querySelector('#btn').addEventListener('click', handler);
// Делегування вручну
document.querySelector('#list').addEventListener('click', (e) => {
if (e.target.matches('.item')) {
// ...
}
});
Багатослівніше на три рядки, зате без залежностей. Замість неймспейсів — іменовані функції, щоб потім знати, що передати у removeEventListener.
Де jQuery ще реально зручніша:
- Делегування в одну стрічку — читається швидше, ніж
e.target.matches()всередині обробника. - Кастомні події з даними — нативний
CustomEventробить те саме, але синтаксис довший. - Неймспейси при знятті обробників — нативний аналог вимагає зберігати посилання на функцію.
Якщо jQuery уже завантажена (WordPress, Bootstrap 4, стара тема) — використовуй. Якщо стартуєш з нуля і питання “чи брати jQuery заради подій” — не треба.
Підсумок
Один .on() замінює пів документації. Запам’ятай його, неймспейси і делегування — решту забудь. Побачиш .live() в чужому коді — посміхнися і заміни на .on().