Разбиране на поведението на JavaScript в Drupal, Master-web
Първо погледнете поведението на Drupal
Ядрото на Drupal ще извика прикачените поведения, когато DOM (HTML Document Object Module) е напълно зареден, предавайки два аргумента:
- контекст (целия DOM по подразбиране)
- настройки , който съдържа обект за настройки, генериран от страната на сървъра
Можем да проверим това, като разгледаме кода вmisc/drupal.js:
Забележка : $(function () е пряк път за $(document).ready().
И ето един важен момент, на който определено трябва да обърнем внимание: Drupal.attachBehaviors() може да бъде извикан повече от веднъж, след като DOM се зареди. Ядрото на Drupal ще извика Drupal.attachBehaviors() в следните случаи:
- След като се извика наслагването на административния панел
- След като формулярът за изпращане на API на AJAX Form се запали
- След като AJAX заявката модифицира DOM, като ajax_command_replace()
Освен това самите модули също извикват Drupal.attachBehaviors() . Ето няколко примера:
След първото извикване на Drupal.attachBehaviors(), контекстната променлива съдържа обекта на документа, представляващ DOM, но при следващи извиквания ще съдържа само частта от HTML, която се променя. Това често се пренебрегва от разработчиците, което води до лош код и JS грешки в браузъра.
Как можем да сме сигурни, че съществуващото поведение на Drupal взема това предвид? В следващия раздел ще отстраним грешки в реален Drupal проект.
Задълбочаване на поведението на Drupal
Когато работите с Drupal проект, можете да зададете точка на прекъсване в дебъгера на Drupal.attachBehaviors() и да видите къде и как се извиква този метод.
След това,тъй като страницата се презарежда, дебъгерът ще спре и ще изчака нашите действия при всяко извикване на Drupal.attachBehaviors()
По-рано казахме, че Drupal ще извика Drupal.attachBehaviors(), след като DOM е напълно зареден. Нека го проверим в дебъгера. По-долу можете да видите променливите за контекст и настройки в панела за обхват на променливата.
Както можете да видите, повечето персонализирани поведения се извикват веднъж и кодът изглежда съвсем нормален на този етап. Но нека проверим дали това е вярно и дали всичко е наред, след като Drupal.attachBehaviors() бъде извикан отново на страницата.
Тестване на поведение при последващи обаждания
Главната страница на сайта Syfy използва Views и Views load more за изграждане на плочката със съдържание. Нека превъртите надолу и щракнете върху „Зареждане на още“, за да видим какво ще се случи:
Контекстната променлива съдържа само региона, който трябва да се актуализира, вместо целия HTML документ. И това е съществен пропуск. Поведения на Drupal, които приемат контекстна променлива като втори аргумент на стандартната функция за търсене на jQuery DOM елемент, например: $('#some-id', context) , няма да се изпълнят, ако няма елемент за търсене в обхвата на контекстния елемент. Много хора изобщо не използват контекстната променлива, когато работят с jQuery селектори - това е често срещана грешка. По-долу е даден пример за едно поведение, при което се вижда грешен подход:
Този код настройва слушател за целия документ за събитието натискане на клавиш Esc, като по този начин прави възможно скриването на менюто.
Какъв е проблемът тук? кодът използва контекстната променлива, за да намери елемента от менюто $('.nav-flyout', context) , но не използва същата променлива, когатозадайте слушателя $(document).keyup(function(e) , което означава, че слушателят ще се добавя всеки път, когато се изпълняват Drupal поведения.
Правилно поведение
За да коригирате ситуацията по-горе, има две възможни решения. Нека разгледаме и двете.
Използване на jQuery Once
В този случай класът за премахване на обработени модали ще бъде добавен, след като кодът бъде изпълнен за първи път. При следващото извикване на Drupal.attachBehaviors(), .once() ще открие дадения клас на елемента и ще пропусне изпълнението на кода.
Използване на контекстната променлива в селектора на jQuery
Много често неизползването на този подход може да причини доста сложно отстраняване на грешки на неочаквани грешки в поведението. По-долу е даден пример, в който използваме контекстната променлива в селекторите:
Този подход е прост и ефективен. jQuery ще намери обекта на документа само в контекстната променлива при първото извикване на Drupal.attachBehaviors(). Този код може да бъде повторно изпълнен само ако Drupal.attachBehaviors(document) бъде извикан някъде, всъщност ситуацията е абсурдна, но трябва да го имате предвид.
алтернатива
В тази ситуация ние напълно игнорираме поведението на Drupal и просто изчакваме DOM да се зареди:
Този код ще работи както трябва и ако не се нуждаете от достъп до полезните неща, които Drupal поведението ни дава, тогава можете също да го използвате. Това е добре.