Skip to content

Все для WordPress, веб-розробки — і не тільки

🔄 JQuery .toggle(): сучасний перемикач і заміна видаленого методу

🔄 JQuery .toggle(): сучасний перемикач і заміна видаленого методу

Знайшли готовий jQuery-сніпет для кнопки «Показати/Сховати», а він не працює? Код із .toggle() писався за мануалом десятирічної давнини й мовчки зламався ще в jQuery 1.9. Для новачка така ситуація виглядає як чорна магія: консоль порожня, помилок немає, кнопка просто не реагує на повторний клік.

Проблема в тому, що метод .toggle() у jQuery мав два життя. Перше, анімація показу/приховування елементів: живе й досі. Друге, чергування дій за кліком: його видалили 2013 року, але пошуковики досі видають старі статті як основні. Тут ми розберемо, чому старий код мертвий, і напишемо три робочі альтернативи, від простого прапорця до data-атрибутів для десятка кнопок одразу.

💡 Швидкий огляд:

  • Чому ваш .toggle(fn1, fn2) не працює і де шукати застарілий код
  • Спосіб 1: змінна стану, для одиничної кнопки, мінімум коду
  • Спосіб 2: .data(), коли кнопок багато й кожна живе своїм життям
  • Бонус: три й більше дій на ланцюжку кліків через лічильник
  • Сучасний .toggle() для анімації, що залишилося і як використовувати

Що таке.toggle() у jQuery і чому старий код мертвий

До jQuery 1.8 метод .toggle() умів дві різні речі залежно від переданих аргументів. Якщо передати два параметри-функції, він працював як перемикач: перший клік запускав першу функцію, другий клік, другу, третій, знову першу, і так по колу.

Виглядало це компактно:

1// Работало в jQuery до 1.8, удалено в 1.9
2$('#myButton').toggle(
3 function() {
4 $(this).text('Показать категории').css('background', 'green');
5 },
6 function() {
7 $(this).text('Скрыть категории').css('background', 'red');
8 }
9);

Саме такий код мандрує російськомовними блогами й досі. Проблема в тому, що з виходом jQuery 1.9 (січень 2013 року) цю форму .toggle() прибрали повністю. Причина, подвійне призначення методу створювало плутанину: новачки не розуміли, чому .toggle() то анімує, то перемикає дії.

Сьогодні .toggle() робить лише одне, показує або приховує елемент з анімацією. А для чергування дій розробнику потрібно явно керувати станом.

Спосіб 1: змінна стану

Найпряміший шлях, завести булеву змінну й перемикати її в обробнику .click(). Підходить для одиничної кнопки або елементів, у яких логіка перемикання спільна.

Додайте код у файл скриптів теми (через wp_enqueue_script у functions.php) або в блок <script> перед закривним </body>:

1let isFirstClick = true;
2
3$('#toggleBtn').on('click', function() {
4 const $btn = $(this);
5
6 if (isFirstClick) {
7 $btn.text('Скрыть категории');
8 $('#contentBlock').show(700);
9 isFirstClick = false;
10 } else {
11 $btn.text('Показать категории');
12 $('#contentBlock').fadeOut('slow');
13 isFirstClick = true;
14 }
15});

Тут isFirstClick зберігає поточний стан зовні обробника. Перший клік показує блок і змінює прапорець на false, другий, приховує й повертає прапорець назад. Жодної магії: ви точно знаєте, яка дія відбудеться зараз і яка, наступною.

Плюс підходу в тому, що прапорець можна скинути з будь-якого місця програми. Скажімо, після AJAX-запиту ви хочете повернути кнопку у вихідне положення, просто isFirstClick = true.

Мінус, одна змінна на всі кнопки. Якщо на сторінці два незалежні перемикачі з класом .toggleBtn, змінна isFirstClick буде спільною для обох. Для такого сценарію, спосіб 2.

Спосіб 2: data-атрибути jQuery

Коли у вас кілька незалежних кнопок (наприклад, у кожного товару в каталозі свій блок із характеристиками), стан потрібно зберігати прямо на DOM-елементі. Метод .data() прив’язує довільні дані до елемента й не забруднює глобальну область видимості.

Завантажте скрипт тим самим способом, через wp_enqueue_script або у футері:

1$('.toggle-btn').on('click', function() {
2 const $btn = $(this);
3 const hasClicked = $btn.data('clicked') || false;
4
5 if (!hasClicked) {
6 $btn.text('Скрыть характеристики').css('background', '#f0f0f0');
7 $btn.next('.specs-block').show(400);
8 $btn.data('clicked', true);
9 } else {
10 $btn.text('Показать характеристики').css('background', '#fff');
11 $btn.next('.specs-block').fadeOut(300);
12 $btn.data('clicked', false);
13 }
14});

Виклик $btn.data('clicked') читає стан конкретно цієї кнопки. Десять кнопок на сторінці, десять ізольованих станів. Жодних конфліктів.

Зверніть увагу: .data() працює з пам’яттю jQuery, а не з HTML-атрибутами data-*. Якщо вам потрібно, щоб стан пережив перезавантаження сторінки, додатково пишіть $btn.attr('data-clicked', 'true') і читайте через .attr().

Бонус: три й більше дій по ланцюжку

Що як кліків має бути не два, а три? Скажімо: перше натискання, показати блок, друге, змінити його вміст, третє, приховати. Тут замість булевого прапорця заводять числовий лічильник:

1$('#multiBtn').on('click', function() {
2 const $btn = $(this);
3 let count = $btn.data('clickCount') || 0;
4
5 switch (count) {
6 case 0:
7 $btn.text('Шаг 1: показать блок');
8 $('#targetBlock').show(500);
9 break;
10 case 1:
11 $btn.text('Шаг 2: загрузить данные');
12 $('#targetBlock').load('/ajax-content');
13 break;
14 case 2:
15 $btn.text('Шаг 3: скрыть');
16 $('#targetBlock').fadeOut(400);
17 count = -1; // следующий клик снова станет case 0
18 break;
19 }
20
21 $btn.data('clickCount', count + 1);
22});

Скидати лічильник (count = -1) має сенс, якщо ланцюжок повинен зациклюватися. Якщо дія разова, просто приберіть скидання, і після третього кліку нічого не відбуватиметься.

Сучасний.toggle() для анімації

Та форма .toggle(), яка вижила, відповідає суто за видимість елементів. Без аргументів, миттєве перемикання. З duration, анімація ширини, висоти й прозорості одночасно.

Базовий сценарій: кнопка «Показати/Сховати меню»:

1$('#menuToggle').on('click', function() {
2 $('#mainMenu').toggle('slow', function() {
3 // колбэк после завершения анимации
4 console.log('Анимация завершена');
5 });
6});

Рядки 'fast' і 'slow' дають 200 і 600 мілісекунд відповідно. Можна передати точне число: .toggle(400), 400 мс.

Корисний прийом: примусовий стан через булевий параметр. .toggle(true) завжди показує елемент, а .toggle(false) завжди приховує. Це зручно у зв’язці із зовнішнім прапорцем зі способу 1:

1let visible = true;
2$('#toggleBtn').on('click', function() {
3 visible = !visible;
4 $('#content').toggle(visible);
5});

Код читається лінійно: прапорець перевернули, елемент прийняв потрібний стан. Жодних умовних if/else навколо видимості.

⁉️🤔 Часті запитання

Чому мій старий код із .toggle(fn1, fn2) не видає помилок у консолі?

Стару форму .toggle() видалено на рівні методу: jQuery просто не знаходить таку сигнатуру й мовчки нічого не робить. Консоль порожня, тому що виклик .toggle(fn1, fn2) для сучасного jQuery — це синтаксично коректний, але безглуздий виклик (аргументи ігноруються). Перевірте версію jQuery: якщо 1.9 або вище, старий код мертвий.

Чи можна підключити jQuery Migrate й не переписувати код?

Формально, так. Плагін jQuery Migrate відновлює видалені методи, включно зі старим .toggle(). Але це тимчасовий милиця: Migrate додає ~10 КБ у стисненому вигляді й розрахований на період переходу, а не на постійну роботу. Якщо сайт на WordPress і jQuery вантажиться з ядра, Migrate там уже є для зворотної сумісності. Але покладатися на нього у власному коді не варто: будь-якої миті його може вимкнути оновлення теми або іншого плагіна.

Що краще, змінна чи data-атрибут?

Для однієї кнопки, змінна (менше коду). Для кількох незалежних кнопок або динамічно додаваних елементів, .data() (ізоляція станів). Якщо кнопки додаються через AJAX після завантаження сторінки, використовуйте делегування: $(document).on('click', '.toggle-btn', function() { ... }).

Чи працює.toggle() на мобільних пристроях?

Так. Сучасний .toggle() (анімація) і всі обробники кліку з цієї статті коректно відпрацьовують на тач-подіях. jQuery нормалізує click для мобільних браузерів починаючи з перших версій. Єдиний нюанс: на iOS до 12-ї версії в елементів без cursor: pointer був затриманий клік, але ця проблема вирішується одним CSS-рядком touch-action: manipulation для кнопки.

Де розміщувати jQuery-код у WordPress?

Три варіанти. Швидкий, плагін Code Snippets: вставляєте JS-код у сніпет із типом «JavaScript», він автоматично підвантажується у футері. Правильний, створити в дочірній темі файл js/toggle.js, зареєструвати його через wp_enqueue_script('my-toggle', get_stylesheet_directory_uri() . '/js/toggle.js', array('jquery'), '1.0', true) у functions.php. Параметр true у кінці відправляє скрипт у футер — це стандарт для коду, що працює з DOM. Не ставте <script> прямо в тіло посту, редактор WordPress обріже тег.

Який підхід обрати для вашого проєкту

Якщо у вас одна кнопка з перемиканням тексту й видимості блоку, беріть змінну стану. Три рядки, поведінка прозора, налагодження тривіальне.

Якщо перемикачів кілька (каталог, панель налаштувань, список елементів із розкриттям), тільки .data(). Глобальна змінна на кілька кнопок породить гонитву станів, яку ви будете налагоджувати довше, ніж написати код за способом 2.

Ланцюжок із трьох і більше кроків, лічильник зі switch. Не ускладнюйте булевими прапорцями те, що природно лягає на числа.

А головне, якщо зустріли в пошуку статтю з .toggle(fn1, fn2), закрийте вкладку. jQuery живий, але той конкретний метод похований у 2013 році.

Освіжити знання із запуску JavaScript-фрагментів на льоту можна в нашому матеріалі про роботу зі сніпетами в Chrome DevTools, знадобиться для швидкої обкатки коду з цієї статті.