Skip to content

Wszystko o WordPressie, tworzeniu stron — i nie tylko

🔄 JQuery .toggle(): nowoczesny przełącznik i zamiana usuniętej metody

🔄 JQuery .toggle(): nowoczesny przełącznik i zamiana usuniętej metody

Znalazł Pan gotowy snippet jQuery do przycisku „Pokaż/Ukryj", a on nie działa? Kod z .toggle() pisany według manuala sprzed dziesięciu lat po cichu przestał działać już w jQuery 1.9. Dla początkującego taka sytuacja wygląda na czarną magię: konsola jest pusta, błędów brak, przycisk po prostu nie reaguje na ponowne kliknięcie.

Problem polega na tym, że metoda .toggle() w jQuery miała dwa życia. Pierwsze, animacja pokazywania/ukrywania elementów: żyje do dziś. Drugie, przełączanie akcji po kliknięciu: usunięto je w 2013 roku, ale wyszukiwarki wciąż podają stare artykuły jako główne. Tutaj rozbierzemy, dlaczego stary kod jest martwy, i napiszemy trzy działające alternatywy, od prostej flagi po data-atrybuty dla tuzina przycisków naraz.

💡 Szybki przegląd:

  • Dlaczego Pana .toggle(fn1, fn2) nie działa i gdzie szukać przestarzałego kodu
  • Sposób 1: zmienna stanu, dla pojedynczego przycisku, minimum kodu
  • Sposób 2: .data(), gdy przycisków jest wiele i każdy żyje własnym życiem
  • Bonus: trzy i więcej akcji w łańcuchu kliknięć przez licznik
  • Współczesne .toggle() do animacji, co zostało i jak używać

Czym jest.toggle() w jQuery i dlaczego stary kod jest martwy

Do jQuery 1.8 metoda .toggle() potrafiła dwie różne rzeczy w zależności od przekazanych argumentów. Jeśli przekazać dwa parametry-funkcje, działała jako przełącznik: pierwsze kliknięcie uruchamiało pierwszą funkcję, drugie kliknięcie, drugą, trzecie, znów pierwszą, i tak w kółko.

Wyglądało to kompaktowo:

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);

Właśnie taki kod wędruje po rosyjskojęzycznych blogach do dziś. Problem w tym, że wraz z wydaniem jQuery 1.9 (styczeń 2013 roku) tę formę .toggle() usunięto całkowicie. Powód: podwójne przeznaczenie metody stwarzało zamieszanie: początkujący nie rozumieli, dlaczego .toggle() raz animuje, a raz przełącza akcje.

Dziś .toggle() robi tylko jedno, pokazuje lub ukrywa element z animacją. A do przełączania akcji programista musi jawnie zarządzać stanem.

Sposób 1: zmienna stanu

Najprostsza droga: założyć zmienną logiczną i przełączać ją w handlerze .click(). Pasuje do pojedynczego przycisku lub elementów, w których logika przełączania jest wspólna.

Proszę dodać kod do pliku skryptów motywu (przez wp_enqueue_script w functions.php) lub w blok <script> przed zamykającym </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});

Tutaj isFirstClick przechowuje bieżący stan na zewnątrz handlera. Pierwsze kliknięcie pokazuje blok i zmienia flagę na false, drugie, ukrywa i zwraca flagę z powrotem. Żadnej magii: dokładnie Pan wie, która akcja wydarzy się teraz, a która następna.

Zaletą podejścia jest to, że flagę można zresetować z dowolnego miejsca programu. Powiedzmy, po zapytaniu AJAX chce Pan przywrócić przycisk do pozycji wyjściowej, po prostu isFirstClick = true.

Wadą: jedna zmienna na wszystkie przyciski. Jeśli na stronie są dwa niezależne przełączniki z klasą .toggleBtn, zmienna isFirstClick będzie wspólna dla obu. Do takiego scenariusza, sposób 2.

Sposób 2: data-atrybuty jQuery

Gdy ma Pan kilka niezależnych przycisków (na przykład przy każdym produkcie w katalogu jest własny blok z charakterystyką), stan trzeba przechowywać bezpośrednio na elemencie DOM. Metoda .data() wiąże dowolne dane z elementem i nie zaśmieca globalnego zakresu widoczności.

Proszę załadować skrypt w ten sam sposób, przez wp_enqueue_script lub w stopce:

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});

Wywołanie $btn.data('clicked') odczytuje stan konkretnie tego przycisku. Dziesięć przycisków na stronie, dziesięć izolowanych stanów. Żadnych konfliktów.

Proszę zwrócić uwagę: .data() pracuje z pamięcią jQuery, a nie z HTML-atrybutami data-*. Jeśli potrzebuje Pan, aby stan przetrwał przeładowanie strony, dodatkowo proszę zapisać $btn.attr('data-clicked', 'true') i odczytywać przez .attr().

Bonus: trzy i więcej akcji w łańcuchu

A co, jeśli kliknięć ma być nie dwa, a trzy? Powiedzmy: pierwsze naciśnięcie, pokaż blok, drugie, zmień jego zawartość, trzecie, ukryj. Tutaj zamiast flagi logicznej zakłada się licznik numeryczny:

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});

Resetowanie licznika (count = -1) ma sens, jeśli łańcuch ma się zapętlać. Jeśli akcja jest jednorazowa, proszę po prostu usunąć resetowanie, a po trzecim kliknięciu nic się nie będzie działo.

Współczesne.toggle() do animacji

Ta forma .toggle(), która przetrwała, odpowiada wyłącznie za widoczność elementów. Bez argumentów, natychmiastowe przełączenie. Z duration, animacja szerokości, wysokości i przezroczystości jednocześnie.

Podstawowy scenariusz: przycisk „Pokaż/Ukryj menu":

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

Łańcuchy 'fast' i 'slow' dają odpowiednio 200 i 600 milisekund. Można przekazać dokładną liczbę: .toggle(400), 400 ms.

Przydatny chwyt: wymuszenie stanu przez parametr logiczny. .toggle(true) zawsze pokazuje element, a .toggle(false) zawsze ukrywa. To wygodne w połączeniu z zewnętrzną flagą ze sposobu 1:

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

Kod czyta się liniowo: flaga została odwrócona, element przyjął żądany stan. Żadnych warunkowych if/else wokół widoczności.

⁉️🤔 Częste pytania

Dlaczego mój stary kod z .toggle(fn1, fn2) nie generuje błędów w konsoli?

Starą formę .toggle() usunięto na poziomie metody: jQuery po prostu nie znajduje takiej sygnatury i po cichu nic nie robi. Konsola jest pusta, ponieważ wywołanie .toggle(fn1, fn2) dla współczesnego jQuery to składniowo poprawny, ale bezsensowny wywołanie (argumenty są ignorowane). Proszę sprawdzić wersję jQuery: jeśli 1.9 lub wyższa, stary kod jest martwy.

Czy można podłączyć jQuery Migrate i nie przepisywać kodu?

Formalnie, tak. Wtyczka jQuery Migrate przywraca usunięte metody, w tym stare .toggle(). Ale to tymczasowa proteza: Migrate dodaje ~10 KB w wersji skompresowanej i jest przeznaczony na okres przejściowy, a nie do stałej pracy. Jeśli strona jest na WordPressie i jQuery ładuje się z rdzenia, Migrate już tam jest dla wstecznej kompatybilności. Ale poleganie na nim we własnym kodzie nie jest wskazane: w każdej chwili może go wyłączyć aktualizacja motywu lub innej wtyczki.

Co lepsze, zmienna czy data-atrybut?

Dla jednego przycisku, zmienna (mniej kodu). Dla kilku niezależnych przycisków lub dynamicznie dodawanych elementów, .data() (izolacja stanów). Jeśli przyciski są dodawane przez AJAX po załadowaniu strony, proszę użyć delegowania: $(document).on('click', '.toggle-btn', function() { ... }).

Czy.toggle() działa na urządzeniach mobilnych?

Tak. Współczesne .toggle() (animacja) i wszystkie handlery kliknięcia z tego artykułu poprawnie obsługują zdarzenia dotykowe. jQuery normalizuje click dla przeglądarek mobilnych począwszy od pierwszych wersji. Jedyny niuans: na iOS do wersji 12. w elementach bez cursor: pointer występowało opóźnione kliknięcie, ale ten problem rozwiązuje jeden wiersz CSS touch-action: manipulation dla przycisku.

Gdzie umieszczać kod jQuery w WordPressie?

Trzy warianty. Szybki, wtyczka Code Snippets: wstawia Pan kod JS do snippetu z typem „JavaScript", automatycznie ładuje się on w stopce. Prawidłowy, utworzyć w motywie potomnym plik js/toggle.js, zarejestrować go przez wp_enqueue_script('my-toggle', get_stylesheet_directory_uri() . '/js/toggle.js', array('jquery'), '1.0', true) w functions.php. Parametr true na końcu wysyła skrypt do stopki, to standard dla kodu pracującego z DOM. Proszę nie wstawiać <script> bezpośrednio w treść posta, edytor WordPressa utnie tag.

Jakie podejście wybrać dla Pana projektu

Jeśli ma Pan jeden przycisk z przełączaniem tekstu i widoczności bloku, proszę wziąć zmienną stanu. Trzy linijki, zachowanie przejrzyste, debugowanie trywialne.

Jeśli przełączników jest kilka (katalog, panel ustawień, lista elementów z rozwijaniem), tylko .data(). Globalna zmienna na kilka przycisków zrodzi gonitwę stanów, którą będzie Pan debugował dłużej, niż napisze kod sposobem 2.

Łańcuch z trzech i więcej kroków, licznik ze switch. Proszę nie komplikować flagami logicznymi tego, co naturalnie układa się na liczbach.

A co najważniejsze, jeśli natknął się Pan w wyszukiwarce na artykuł z .toggle(fn1, fn2), proszę zamknąć kartę. jQuery żyje, ale ta konkretna metoda została pogrzebana w 2013 roku.

Odświeżyć wiedzę z uruchamiania fragmentów JavaScript na bieżąco można w naszym materiale o pracy ze snippetami w Chrome DevTools, przyda się do szybkiego obiegania kodu z tego artykułu.