Drupal에서 JavaScript 길들이기(FAQ 포함)

게시 됨: 2023-02-07

대화형 웹 경험은 사용자에게 보다 매력적이고 즐거운 경험을 제공합니다. 이는 사용자 만족도를 높이고 웹 사이트에 대한 긍정적인 인식으로 이어집니다. 예를 들어 사용자가 페이지 새로고침을 기다리게 하는 대신 즉각적인 피드백과 확인을 제공하는 양식은 사용자 경험을 크게 향상시킬 수 있습니다.

JavaScript는 Drupal 웹 사이트의 프런트엔드에서 사용자를 위한 동적 및 대화형 경험을 생성하는 수단을 제공함으로써 Drupal에서 중요한 역할을 합니다. 이를 통해 개발자는 전체 페이지를 새로 고치지 않고도 양식, 링크 또는 기타 DOM 요소와 같은 페이지의 특정 요소 동작을 수정할 수 있습니다. Drupal 동작은 페이지에서 특정 이벤트가 발생할 때 실행되는 JavaScript 함수입니다. 동작을 통해 개발자는 기본 HTML 코드를 변경할 필요가 없으므로 사이트를 쉽게 유지 관리하고 업그레이드할 수 있습니다. 문서에서 Drupal 행동에 대해 알고 싶었던 모든 것을 찾아보십시오.

Drupal에서 JavaScript 길들이기

Drupal 행동이란 무엇입니까?

Drupal.behaviors 는 Drupal의 Javascript 구조 내부에 있는 개체로, 애플리케이션 실행 중 특정 시간에 실행할 함수를 첨부할 수 있습니다. DOM이 완전히 로드되었을 때 호출되지만 이러한 동작은 다시 호출될 수 있습니다. Drupal의 공식 JavaScript 문서에서는 모듈이 Drupal.behaviors 에 로직을 첨부하여 JavaScript를 구현해야 한다고 제안합니다.

Drupal 동작이 필요한 이유는 무엇입니까?

비헤이비어의 장점은 AJAX를 통해 로드되는 모든 콘텐츠에 자동으로 다시 적용된다는 것입니다. DOM에 대한 새로운 추가 또는 변경 사항을 나타내는 컨텍스트로 언제든지 호출할 수 있습니다. 코드가 한 번만 실행되는 $(document).ready() 또는 document DOMContentLoaded 보다 낫습니다.

Drupal 행동이 원치 않는 경우는 언제입니까?

Drupal 동작이 항상 Drupal에서 Javascript를 작성하기 위한 완벽한 솔루션은 아닙니다. 어떤 경우에는 아래에 명시된 바와 같이 Drupal 동작이 전혀 필요하지 않습니다!

  • DOM에 영향을 주지 않는 코드를 실행해야 할 때. 예. Google 애널리틱스와 같은 외부 스크립트 초기화
  • 페이지가 로드될 때 요소를 사용할 수 있음을 알고 DOM에서 일부 JS 작업을 한 번만 수행해야 하는 경우(이 시나리오는 한 번 사용하는 것과 다릅니다).

Drupal 행동은 언제 호출됩니까?

  • 관리 오버레이가 페이지에 로드된 후.
  • AJAX Form API가 양식을 제출한 후.
  • AJAX 요청이 ajax_command_replace() 와 같이 HTML을 수정하는 명령을 반환하는 경우.

Drupal 행동이 호출되는 다른 시간

  • CTools는 모달이 로드된 후 호출합니다.
  • 미디어는 미디어 브라우저가 로드된 후 호출합니다.
  • 내부 편집이 완료된 후 패널에서 호출합니다.
  • Views는 AJAX를 사용하는 새 페이지를 로드한 후 호출합니다.
  • Views Load More는 다음 청크 항목을 로드한 후 호출합니다.
  • 사용자 정의 모듈의 JavaScript는 페이지의 일부를 추가하거나 변경할 때 Drupal.attachBehaviors() 를 호출할 수 있습니다.

Drupal 비헤이비어 없이 코드 작성

이 코드에서는 이 행을 클릭하는 횟수를 계산하는 .views-row 클래스에 클릭 이벤트 리스너 를 추가합니다. 그러나 초기 페이지 로드 중에 DOM에 들어오는 요소에는 한 번만 추가됩니다. 추가 로드를 클릭하고 더 많은 항목을 로드하면 클릭 리스너가 새로 로드된 항목에서 작동하지 않습니다.

 // 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; }); }); })(); 
이벤트 리스너

Drupal 행동을 어떻게 사용합니까?

답변: 첨부 방법 사용

기억해야 할 사항:

  • 새 개체에는 최소한 첨부 방법이 있어야 합니다.
  • Drupal.attachBehaviors가 호출될 때마다 모든 비헤이비어 개체를 반복하고 각각의 연결 메서드를 호출합니다.

코드에 Drupal 동작 추가

Drupal Behaviors를 추가한 후 코드는 다음과 같습니다.

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

그러나 Load More를 클릭하면 상단에 이상한 것이 나타납니다.

행동

이는 Drupal 동작이 여러 번 호출되고 이후에 의도하지 않은 동작이 발생하기 때문입니다.

"Drupal 컨텍스트"에서 컨텍스트란 무엇입니까?

  • 모든 동작에 대해 연결 메서드를 호출할 때 Drupal은 컨텍스트 매개 변수를 함께 전달합니다.
  • 전달되는 컨텍스트 매개변수는 종종 어떤 DOM 요소가 처리되고 있는지 더 잘 알 수 있습니다.
  • 초기 페이지 로드 중에 이것은 완전한 HTML 문서가 됩니다. 후속 호출 중에 이것은 페이지에 추가되거나 수정되는 요소일 뿐입니다.

컨텍스트를 추가하는 방법?

이전 문제는 Drupal Behaviors에서 제공하는 context 매개변수를 사용하여 해결할 수 있습니다. 이 경우 페이지가 처음 로드될 때 전체 HTML 문서를 컨텍스트로 가져오고 이때 헤더를 첨부합니다. 추가 작업을 위해 Drupal Behaviors의 영향을 받는 코드의 일부이므로 코드의 해당 부분이 안전하게 제어됩니다.

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

다시 Load More 를 클릭하면 몇 가지 이상한 동작이 있습니다. 처음에 로드된 식품 항목은 정상적으로 작동합니다. 그러나 Load More를 클릭하면 새 항목이 클릭 수신기를 가져오고 정상적으로 작동합니다. 그러나 초기에 로드된 항목은 리스너를 다시 연결하고 해당 항목을 클릭하면 클릭 이벤트가 두 번 이상 호출됩니다!

더 로드

Drupal Behaviors는 언제 오작동을 시작합니까?

  • Once 및 Context를 사용하지 않고 Drupal 동작 내에서 모든 이벤트 리스너를 작성합니다.
  • 첨부 메서드가 호출될 때마다 함수를 재선언하도록 하는 Drupal 동작 내에서 원하지 않는 함수를 선언합니다.

구조에 "한 번"

  • Once는 코드가 실행된 후 DOM 요소에 data-once 속성을 추가하여 무언가가 한 번만 처리되도록 합니다.
  • 동작이 다시 호출되면 추가 실행을 위해 data-once 특성이 있는 요소를 건너뜁니다.
  • Once는 jQuery.once 의 최신 구현입니다(jQuery에서 벗어나려는 노력).
  • 일단 컨텍스트와 결합하여 필요에 따라 전체 기능을 완벽하게 제어합니다.

코드에서 이벤트 리스너를 수정하기 위해 Once 추가

 (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);
데이터 한 번

이제 모든 것이 의도한 대로 작동합니다. 이벤트 리스너가 연결된 요소에 대해 data-once 특성을 가져오고 새로 로드된 요소와 이전에 로드된 요소가 제대로 작동합니다.

분리 방법의 필요성

Detach 방법은 우리가 attach 방법에서 수행한 모든 작업을 제거하는 안티 히어로(사악하지 않음)처럼 작동합니다. detach 메서드의 모든 코드는 콘텐츠가 DOM에서 제거될 때마다 호출됩니다. 이는 애플리케이션을 정리하는 데 도움이 됩니다. 예를 들어 Detach 메서드를 사용하면 지속적인 폴링 상황과 같이 리소스를 소비하는 원치 않는 이벤트 리스너를 제거할 수 있습니다.

분리의 예

채울 ajax 양식이 있고 경과 시간을 표시하기 위해 타이머를 사용하고 있다고 가정합니다. setTimeOut을 사용하여 타이머를 관리합니다. 모니터링을 위해 이 타이머를 콘솔에 기록합니다.

 (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);
제한 시간 설정

양식 제출 시 DOM의 타이머가 제거되지만 콘솔에서 오류가 발생하기 시작합니다. 이는 setTimeOut이 작동하는 요소가 DOM에서 제거되었기 때문입니다.

분리하다

이를 방지하기 위해 다음과 같이 분리 방법을 사용할 수 있습니다.

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

이렇게 하면 언로드 시 타이머가 제거되고 로거에서 볼 수 있듯이 오류가 발생하지 않습니다.

JS 데모

즉시 호출 함수 표현식(IIFE) - JS용 래퍼

우리는 Drupal 코드를 작성하기 위해 IIFE를 사용하고 있습니다. 초기 여는 괄호는 함수 범위가 전체 응용 프로그램의 전역 범위를 오염시키지 않도록 하는 익명 함수를 정의합니다. 함수 정의 끝에 인수를 인수로 포함하여 익명 함수에 인수를 전달할 수 있습니다.

이것은 또한 우리가 매개 변수를 사용하기를 원하지만 이름을 지정하는 데 도움이 됩니다.

예:

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

마지막 생각들

Drupal 동작을 구현하면 동적 상호 작용, 간소화된 사용자 상호 작용, 개선된 사용자 피드백, 효율적인 개발 및 웹 사이트의 전반적인 사용자 경험이 향상됩니다. Drupal.behavior는 페이지에서 여러 번 실행할 수 있고 기존 동작을 재정의 및 확장할 수 있으며 Ajax를 통해 로드된 모든 콘텐츠에 자동으로 다시 적용할 수 있다는 점에서 유연하고 모듈식입니다.

대화형 웹 경험을 구축하고 Drupal을 최대한 활용할 수 있도록 도와줄 Drupal 개발 에이전시를 찾고 계십니까? 우리는 이야기하고 싶습니다!