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, пригодится для быстрой обкатки кода из этой статьи.