Oswajanie JavaScript w Drupalu (zawiera często zadawane pytania)
Opublikowany: 2023-02-07Interaktywne środowiska internetowe zapewniają użytkownikom bardziej wciągające i przyjemniejsze wrażenia. Prowadzi to do wzrostu satysfakcji użytkowników i pozytywnego postrzegania serwisu. Na przykład formularz, który zapewnia natychmiastową informację zwrotną i weryfikację, zamiast zmuszać użytkownika do oczekiwania na odświeżenie strony, może znacznie poprawić komfort użytkowania.
JavaScript odgrywa ważną rolę w Drupalu, zapewniając środki do tworzenia dynamicznych i interaktywnych doświadczeń dla użytkowników na froncie witryny Drupala. Umożliwia programistom modyfikowanie zachowania niektórych elementów na stronie, takich jak formularze, linki lub inne elementy DOM, bez konieczności odświeżania całej strony. Zachowania Drupala to funkcje JavaScript, które są wykonywane, gdy na stronie wystąpią określone zdarzenia. Zachowania ułatwiają programistom utrzymanie i uaktualnianie witryny, ponieważ nie muszą zmieniać żadnego bazowego kodu HTML. Dowiedz się wszystkiego, co chciałeś wiedzieć o Drupal Behaviors w artykule.
Czym są zachowania Drupala?
Drupal.behaviors to obiekt wewnątrz struktury Javascript w Drupalu, który pozwala nam dołączać funkcje do wykonania w określonych momentach podczas wykonywania aplikacji. Jest wywoływana, gdy DOM jest w pełni załadowany, ale te zachowania można wywołać ponownie. Oficjalna dokumentacja JavaScript Drupala sugeruje, że moduły powinny implementować JavaScript poprzez dołączenie logiki do Drupal.behaviors .
Po co nam zachowania Drupala?
Zaletą zachowań jest to, że są one automatycznie ponownie stosowane do dowolnej treści ładowanej przez AJAX. Można je wywołać w dowolnym momencie z kontekstem reprezentującym nowe dodatki lub zmiany w modelu DOM. Jest to lepsze niż $(document).ready() lub document DOMContentLoaded , gdzie kod jest uruchamiany tylko raz.
Kiedy zachowania Drupala są niepożądane?
Zachowania Drupala nie zawsze są idealnym rozwiązaniem do pisania Javascript w Drupalu. W niektórych przypadkach, jak stwierdzono poniżej, zachowania Drupala nie są w ogóle potrzebne!
- Kiedy musimy wykonać jakiś kod, który nie wpływa na DOM. Np. Inicjowanie zewnętrznego skryptu, takiego jak Google Analytics
- Gdy jakaś operacja JS musi zostać wykonana na DOM tylko raz, wiedząc, że element będzie dostępny po załadowaniu strony (Ten scenariusz różni się od jednorazowego użycia).
Kiedy nazywane są zachowania Drupala?
- Po załadowaniu nakładki administracyjnej na stronę.
- Po przesłaniu formularza przez interfejs AJAX Form API.
- Gdy żądanie AJAX zwraca polecenie, które modyfikuje kod HTML, na przykład ajax_command_replace() .
Innym razem, gdy wywoływane są zachowania Drupala
- CTools wywołuje to po załadowaniu modalu.
- Media wywołuje to po załadowaniu przeglądarki multimediów.
- Panels wywołuje to po zakończeniu edycji w miejscu.
- Views wywołuje to po załadowaniu nowej strony, która używa AJAX.
- Views Load More wywołuje to po załadowaniu kolejnej porcji elementów.
- JavaScript z modułów niestandardowych może wywoływać Drupal.attachBehaviors() , gdy dodają lub zmieniają części strony.
Pisanie kodu bez zachowań Drupala
W tym kodzie dodajemy detektor zdarzeń kliknięcia do klasy .views-row , który oblicza, ile razy klikamy ten wiersz. Ale jest dodawany tylko raz do elementów, które pojawiają się w DOM podczas początkowego ładowania strony. Po kliknięciu przycisku Załaduj więcej i załadowaniu większej liczby elementów odbiornik kliknięć nie działa na nowo załadowanych elementach.
// No Drupal Behaviors (function () { let header = document.querySelector(".food-list-header"); if (header) { let greatFoodSpan = document.createElement("span"); greatFoodSpan.textContent = "Get ready for great food!!!!!!"; header.append(greatFoodSpan); } // Add the event listener for each click on the food let foods = document.querySelectorAll(".views-row"); foods.forEach((food) => { food.addEventListener("click", () => { let foodCounter = food.querySelector(".food-click-counter"); let timesClicked = parseInt(foodCounter.textContent.trim()); foodCounter.textContent = ++timesClicked; }); }); })();
Jak wykorzystujemy zachowania Drupala?
Odpowiedź: Za pomocą metody attach
Rzeczy do zapamiętania:
- Nowy obiekt musi mieć przynajmniej metodę attach.
- Za każdym razem, gdy zostanie wywołana metoda Drupal.attachBehaviors, będzie ona przechodzić przez wszystkie obiekty zachowań i wywoływać odpowiednie metody dołączania.
Dodanie zachowania Drupala do naszego kodu
Po dodaniu Zachowań Drupala kod wygląda mniej więcej tak.
(function (Drupal) { Drupal.behaviors.exampleBehaviour1 = { attach: (context, settings) => { // Add a delicious text to the top of the document let header = document.querySelector(".food-list-header"); // jQuery Equivalent // $(".food-list-header"); if (header) { let greatFoodSpan = document.createElement("span"); greatFoodSpan.textContent = "Get ready for great food!!!!!!"; header.append(greatFoodSpan); } // Add the event listener for each click on the food let foods = document.querySelectorAll(".views-row"); foods.forEach((food) => { food.addEventListener("click", () => { let foodCounter = food.querySelector(".food-click-counter"); let timesClicked = parseInt(foodCounter.textContent.trim()); foodCounter.textContent = ++timesClicked; }); }); }, }; })(Drupal);
Ale coś dziwnego pojawia się na górze, kiedy klikamy Załaduj więcej:
Dzieje się tak, ponieważ zachowanie Drupala jest wywoływane wiele razy, a następnie otrzymujemy niezamierzone zachowanie.
Czym jest kontekst w „kontekście Drupala”?
- Podczas wywoływania metody attach dla wszystkich zachowań Drupal przekazuje parametr kontekstu .
- Przekazywany parametr context często daje lepsze wyobrażenie o przetwarzanym elemencie DOM.
- Podczas początkowego ładowania strony będzie to kompletny dokument HTML; podczas kolejnych wywołań będą to tylko te elementy, które są dodawane do strony lub ulegają modyfikacji.
Jak dodać kontekst?
Poprzedni problem można rozwiązać za pomocą parametru context , który jest dostarczany przez Drupal Behaviors. W tym przypadku, gdy strona ładuje się po raz pierwszy, otrzymujemy cały dokument HTML jako kontekst i wtedy dołączamy nagłówek. W przypadku dalszych operacji będzie to część kodu, na którą mają wpływ Zachowania Drupala, a zatem ta część kodu jest bezpiecznie kontrolowana.
(function (Drupal) { Drupal.behaviors.exampleBehaviour2 = { attach: (context, settings) => { // Add a delicious text to the top of the document. // The context parameter now can be used for adding // certain functionality which removes unwanted repeatability let header = context.querySelector(".food-list-header"); // jQuery Equivalent // $(".food-list-header", context); if (header) { let greatFoodSpan = document.createElement("span"); greatFoodSpan.textContent = "Get ready for great food!!!!!!"; header.append(greatFoodSpan); } // Add the event listener for each click on the food let foods = context.querySelectorAll(".views-row"); foods.forEach((food) => { food.addEventListener("click", () => { let foodCounter = food.querySelector(".food-click-counter"); let timesClicked = parseInt(foodCounter.textContent.trim()); foodCounter.textContent = ++timesClicked; }); }); }, }; })(Drupal);
Ponownie pojawia się dziwne zachowanie, gdy klikamy Load More . Artykuły spożywcze, które zostały początkowo załadowane, działają dobrze. Ale po kliknięciu Załaduj więcej nowe elementy otrzymują odbiornik kliknięć i działają normalnie. Ale początkowo załadowane elementy ponownie przywiązują słuchacza, a kliknięcie ich wywołuje zdarzenie kliknięcia więcej niż jeden raz!
Kiedy zachowania Drupala zaczynają się źle zachowywać?
- Pisanie wszystkich detektorów zdarzeń w zachowaniach Drupala bez użycia Razu i Kontekstu.
- Deklarowanie niechcianych funkcji wewnątrz zachowań Drupala, co prowadzi do ponownego deklarowania funkcji za każdym razem, gdy wywoływana jest metoda attach.
„Raz” na ratunek
- Raz gwarantuje, że coś zostanie przetworzone tylko raz, dodając atrybut data-once w elemencie DOM po wykonaniu kodu.
- Jeśli zachowanie zostanie wywołane ponownie, element z atrybutem data-once zostanie pominięty do dalszego wykonania.
- Once to nowoczesna implementacja jQuery.once (co jest próbą odejścia od jQuery)
- Raz, w połączeniu z kontekstem, kontroluje całą funkcjonalność idealnie tak, jak tego potrzebujemy.
Dodanie Once, aby naprawić detektory zdarzeń w naszym kodzie
(function (Drupal, once) { Drupal.behaviors.exampleBehaviour3 = { attach: (context, settings) => { once("food-header-initialized", ".food-list-header", context).forEach( (header) => { let greatFoodSpan = document.createElement("span"); greatFoodSpan.textContent = "Get ready for great food!!!!!!"; header.append(greatFoodSpan); } ); // jQuery Equivalent // $(".food-list-header", context).once("food-header-initialized", function (header) { // // }); // Add the event listener for each click on the food once("food-initialized", ".views-row", context).forEach((food) => { food.addEventListener("click", () => { let foodCounter = food.querySelector(".food-click-counter"); let timesClicked = parseInt(foodCounter.textContent.trim()); foodCounter.textContent = ++timesClicked; }); }); }, }; })(Drupal, once);
Teraz wszystko działa zgodnie z przeznaczeniem. Otrzymujemy atrybut data-once do elementów, do których są dołączone detektory zdarzeń i elementy nowo załadowane oraz elementy wcześniej załadowane działają poprawnie.
Metoda Need for Detach
Metoda Detach działa jak antybohater (nie zło), usuwając wszystko, co zrobiliśmy w metodzie attach. Każdy kod w metodzie detach zostanie wywołany za każdym razem, gdy zawartość zostanie usunięta z modelu DOM. To pomaga nam oczyścić naszą aplikację. Na przykład metoda Detach pozwala nam usunąć niechciane detektory zdarzeń, które zużywają zasoby, takie jak sytuacja ciągłego odpytywania.
Przykłady Odłącz
Załóżmy, że mamy formularz ajax do wypełnienia i używamy licznika czasu, aby pokazać czas, który upłynął. Używamy setTimeOut do zarządzania timerem. Logujemy ten timer w konsoli w celu monitorowania.
(function (Drupal, once) { let counter = 0; Drupal.behaviors.exampleBehaviour4 = { attach: (context, settings) => { once("timer-initalized", ".contact-timer", context).forEach((ele) => { const timer = context.querySelector(".contact-timer-sec"); timer.textContent = counter; // Set the timer for user to see the time elapsed setInterval(() => { console.log("This is logging"); const timer = document.querySelector(".contact-timer-sec"); timer.textContent = ++counter; }, 1000); }); }, }; })(Drupal, once);
Po przesłaniu formularza licznik czasu w DOM zostaje usunięty, ale konsola zaczyna zgłaszać błąd. Dzieje się tak, ponieważ element, na którym działa setTimeOut, został usunięty z DOM:
Aby tego uniknąć, możemy użyć metody odłączania w następujący sposób:
(function (Drupal, once) { let counter = 0; let intervalStopper; Drupal.behaviors.exampleBehaviour4 = { attach: (context, settings) => { // Set the timer for user to see the time elapsed once("timer-initialized", ".contact-timer", context).forEach((ele) => { const timer = context.querySelector(".contact-timer-sec"); timer.textContent = counter; intervalStopper = setInterval(() => { const timer = document.querySelector(".contact-timer-sec"); timer.textContent = ++counter; console.log("This is logging"); }, 1000); }); }, // Clear the timer on confirmation detach: (context, settings, trigger) => { const timer = context.querySelector(".contact-timer-sec"); if (trigger == "unload" && timer) { clearInterval(intervalStopper); } }, }; })(Drupal, once);
Spowoduje to usunięcie licznika czasu przy wyładowaniu i, jak widać z rejestratora, błąd nie występuje.
Natychmiast wywołane wyrażenia funkcyjne (IIFE) — opakowanie dla JS
Używamy IIFE do pisania naszego kodu Drupala. Początkowe nawiasy otwierające definiują funkcję anonimową, która pomaga zapobiegać zanieczyszczaniu zakresu funkcji przez zasięg globalny całej aplikacji. Argumenty można przekazywać do funkcji anonimowej, umieszczając je jako argumenty na końcu definicji funkcji.
Pomaga nam to również w nazwaniu parametrów w sposób, w jaki chcemy, aby były używane.
Przykład:
// Function name crisis!!!! // The function is vulnearble to // be replaced by some other function function someFunction() { // Some code for this function } (function (Drupal) { // Function name crisis averted! function someFunction() { // Some code for this other function } Drupal.behaviors.exampleBehaviour6 = { attach: (context, settings) => { someFunction(); }, }; })(Drupal);
Końcowe przemyślenia
Implementacja zachowań Drupala pozwala na dynamiczną interaktywność, usprawnioną interakcję użytkownika, lepszą informację zwrotną od użytkownika, efektywny rozwój i ogólnie lepsze wrażenia użytkownika z Twojej witryny. Drupal.behaviors są elastyczne i modułowe, ponieważ mogą być wykonywane wiele razy na stronie, mogą zastępować i rozszerzać istniejące zachowanie oraz mogą być automatycznie ponownie stosowane do dowolnej treści ładowanej przez Ajax.
Szukasz agencji zajmującej się rozwojem Drupala, która pomoże Ci tworzyć interaktywne doświadczenia internetowe, wykorzystując w pełni możliwości Drupala? Chętnie porozmawiamy!