ترويض JavaScript في دروبال (يشمل الأسئلة الشائعة)
نشرت: 2023-02-07توفر تجارب الويب التفاعلية تجربة أكثر جاذبية وإمتاعًا للمستخدمين. يؤدي إلى زيادة رضا المستخدم وتصور إيجابي لموقع الويب. على سبيل المثال ، يمكن للنموذج الذي يوفر ملاحظات فورية والتحقق من الصحة ، بدلاً من جعل المستخدم ينتظر تحديث الصفحة ، أن يحسن تجربة المستخدم بشكل كبير.
تلعب JavaScript دورًا مهمًا في دروبال من خلال توفير الوسائل لإنشاء تجارب ديناميكية وتفاعلية للمستخدمين على الواجهة الأمامية لموقع ويب دروبال. إنه يمكّن المطورين من تعديل سلوك عناصر معينة على الصفحة ، مثل النماذج أو الروابط أو أي عناصر DOM أخرى ، دون الحاجة إلى تحديث الصفحة بأكملها. سلوكيات Drupal هي وظائف JavaScript يتم تنفيذها عند وقوع أحداث معينة على الصفحة. تُسهل السلوكيات على المطورين صيانة الموقع وترقيته حيث لا يحتاجون إلى تغيير أي كود HTML أساسي. اكتشف كل ما تريد معرفته عن سلوكيات دروبال في المقالة.
ما هي سلوكيات دروبال؟
Drupal.behaviors هو كائن داخل بنية Javascript في دروبال ، والذي يسمح لنا بإرفاق وظائف ليتم تنفيذها في أوقات معينة أثناء تنفيذ التطبيق. يتم استدعاؤه عندما يتم تحميل DOM بالكامل ، ولكن يمكن استدعاء هذه السلوكيات مرة أخرى. تقترح وثائق JavaScript الرسمية من Drupal أن الوحدات النمطية يجب أن تنفذ JavaScript من خلال إرفاق المنطق بـ Drupal.behaviors .
لماذا نحتاج إلى سلوكيات دروبال؟
تتمثل ميزة السلوكيات في إعادة تطبيقها تلقائيًا على أي محتوى يتم تحميله عبر AJAX. يمكن استدعاؤها في أي وقت بسياق يمثل إضافات أو تغييرات جديدة على DOM. هذا أفضل من $ (document) .ready () أو مستند DOMContentLoaded حيث يتم تشغيل الكود مرة واحدة فقط.
متى تكون سلوكيات دروبال غير مرغوب فيها؟
سلوكيات دروبال ليست دائمًا الحل الأمثل لكتابة جافا سكريبت في دروبال. في بعض الحالات ، كما هو مذكور أدناه ، ليست هناك حاجة لسلوكيات دروبال على الإطلاق!
- عندما نحتاج إلى تنفيذ بعض التعليمات البرمجية التي لا تؤثر على DOM. على سبيل المثال. تهيئة برنامج نصي خارجي مثل Google Analytics
- عندما يلزم تنفيذ بعض عمليات JS على DOM مرة واحدة فقط مع العلم أن العنصر سيكون متاحًا عند تحميل الصفحة (هذا السيناريو يختلف عن استخدام مرة واحدة).
متى يتم استدعاء سلوكيات دروبال؟
- بعد تحميل تراكب الإدارة في الصفحة.
- بعد أن تقوم واجهة برمجة تطبيقات نموذج AJAX بإرسال نموذج.
- عندما يقوم طلب AJAX بإرجاع أمر يعدل HTML ، مثل ajax_command_replace () .
في أوقات أخرى يتم استدعاء سلوكيات دروبال
- تستدعيه CTools بعد تحميلها.
- تستدعيها الوسائط بعد تحميل متصفح الوسائط.
- تستدعيه اللوحات بعد اكتمال التحرير الموضعي.
- تستدعيها المشاهدات بعد تحميل صفحة جديدة تستخدم AJAX.
- المشاهدات تحميل المزيد من المكالمات بعد تحميل الجزء التالي من العناصر.
- قد تقوم JavaScript من الوحدات المخصصة باستدعاء Drupal.attachBehaviors () عند إضافة أجزاء من الصفحة أو تغييرها.
كتابة التعليمات البرمجية بدون سلوكيات دروبال
في هذا الكود ، نضيف مستمع حدث click إلى فئة صف العرض .views التي تحسب عدد المرات التي نضغط فيها على هذا الصف. لكنها تضاف مرة واحدة فقط إلى العناصر التي تأتي في 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.attachBehaviors ، وسوف يتكرر خلال جميع كائنات السلوك ويستدعي أساليب الإرفاق الخاصة بكل منها.
إضافة سلوك دروبال إلى التعليمات البرمجية الخاصة بنا
بعد إضافة 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);
ولكن يظهر شيء غريب في الجزء العلوي عندما نضغط على تحميل المزيد:
هذا بسبب استدعاء سلوك دروبال في كثير من الأحيان ، وبالتالي نحصل على بعض السلوك غير المقصود.
ما هو السياق في "سياق دروبال"؟
- عند استدعاء التابع attach لجميع السلوكيات ، يمر دروبال بمعامل سياق .
- غالبًا ما تعطي معلمة السياق التي تم تمريرها فكرة أفضل عن عنصر DOM الذي تتم معالجته.
- أثناء تحميل الصفحة الأولى سيكون هذا هو مستند HTML الكامل ؛ أثناء الاستدعاءات اللاحقة ، ستكون هذه مجرد العناصر التي تتم إضافتها إلى الصفحة أو تعديلها.
كيف تضيف السياق؟
يمكن حل المشكلة السابقة باستخدام معلمة السياق التي توفرها Drupal Behaviors. في هذه الحالة ، في المرة الأولى التي يتم فيها تحميل الصفحة ، نحصل على مستند HTML بالكامل كسياق وذلك عندما نرفق العنوان. لمزيد من العمليات ، سيكون جزءًا من الكود يتأثر بسلوك دروبال وبالتالي يتم التحكم في هذا الجزء من الكود بأمان.
(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);
مرة أخرى ، هناك بعض السلوكيات الغريبة عندما نضغط على تحميل المزيد . المواد الغذائية التي تم تحميلها في البداية تعمل بشكل جيد. ولكن بعد النقر فوق تحميل المزيد ، تحصل العناصر الجديدة على مستمع النقرات وتعمل بشكل طبيعي. لكن العناصر التي تم تحميلها في البداية تعلق المستمع مرة أخرى والنقر عليها يستدعي حدث النقر أكثر من مرة!
متى تبدأ سلوكيات دروبال في سوء التصرف؟
- كتابة جميع مستمعي الأحداث داخل سلوكيات دروبال دون استخدام مرة واحدة والسياق.
- إعلان وظائف غير مرغوب فيها داخل سلوكيات دروبال مما يؤدي إلى إعادة تعريف الوظائف في كل مرة يتم استدعاء التابع attach.
"مرة واحدة" للإنقاذ
- بمجرد التأكد من معالجة شيء ما مرة واحدة فقط عن طريق إضافة سمة بيانات مرة واحدة في عنصر DOM بعد تنفيذ الكود.
- إذا تم استدعاء السلوك مرة أخرى ، فسيتم تخطي العنصر الذي يحتوي على سمة البيانات مرة واحدة لمزيد من التنفيذ.
- مرة واحدة هي تطبيق حديث لـ jQuery.once (وهي محاولة للابتعاد عن jQuery)
- مرة واحدة ، بالاقتران مع السياق ، تتحكم في الوظيفة بالكامل تمامًا كما نحتاجها.
إضافة مرة لإصلاح مستمعي الحدث في التعليمات البرمجية الخاصة بنا
(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);
الآن كل شيء يعمل على النحو المنشود. نحصل على سمة بيانات مرة واحدة للعناصر حيث يتم إرفاق مستمعي الأحداث وتعمل العناصر المحملة حديثًا والعناصر المحملة مسبقًا بشكل صحيح.
الحاجة إلى طريقة الفصل
تعمل طريقة Detach كمضاد للبطل (وليس شريرًا) ، حيث تزيل كل ما فعلناه في طريقة attach. سيتم استدعاء أي كود في طريقة detach كلما تمت إزالة المحتوى من DOM. هذا يساعدنا على تنظيف تطبيقنا. على سبيل المثال ، تمكننا طريقة Detach من إزالة مستمعي الأحداث غير المرغوب فيهم الذين يستهلكون موارد مثل حالة الاقتراع المستمر.
أمثلة على الفصل
افترض أن لدينا نموذج أياكس لملئه وأننا نستخدم مؤقتًا لإظهار الوقت المنقضي. نستخدم 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);
هذا يزيل عداد الوقت عند التفريغ وكما رأينا من المسجل ، لا يحدث الخطأ.
تم استدعاء تعبيرات الوظائف فورًا (IIFE) - غلاف JS
لقد استخدمنا 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. بالمرونة والوحدات النمطية ، حيث يمكن تنفيذها عدة مرات على الصفحة ، ويمكنها تجاوز السلوك الحالي وتوسيع نطاقه ، ويمكن إعادة تطبيقها تلقائيًا على أي محتوى تم تحميله عبر Ajax.
هل تبحث عن وكالة تطوير دروبال لمساعدتك في بناء تجارب ويب تفاعلية ، وتحقيق أقصى استفادة من دروبال؟ نحب التحدث!