Розуміння JavaScript behaviors у Drupal, Master-web

Перший погляд на Drupal behaviors

Ядро Drupal буде викликати прикріплені behaviors, коли DOM (об'єктний модуль документа HTML) буде повністю завантажений, передаючи два аргументи:

  • context (за замовчуванням весь DOM)
  • settings , який містить об'єкт налаштувань, що формується на стороні сервера

Ми можемо переконатися в цьому, якщо подивимося на код уmisc/drupal.js:

Зверніть увагу : $(function () є шорткатом для $(document).ready().

І тут є важливий момент, на який ми повинні обов'язково звернути увагу: Drupal.attachBehaviors() може бути викликаний більше одного разу після того, як DOM завантажений. Ядро Drupal буде викликати Drupal.attachBehaviors() у таких випадках:

  • Після того, як оверлів панелі адміністратора буде викликано
  • Після того, як спрацьовує сабміт форми AJAX Form API
  • Після того, як AJAX запит модифікує DOM, наприклад, ajax_command_replace()

Більше того, самі модулі викликають Drupal.attachBehaviors() . Ось кілька прикладів:

Після першого виклику Drupal.attachBehaviors() , змінна context містить об'єкт документа, що представляє DOM, але при наступних викликах вона міститиме лише ту частину HTML, яка модифікується. Це часто не береться до уваги розробниками, що призводить до створення поганого коду і помилок JS в браузері.

Як ми можемо переконатися, що існуючі Drupal behaviors враховують це? У наступному розділі ми зробимо налагодження на реальному проекті Drupal.

Поглиблюємося Drupal behaviors

Коли ви працюєте з Drupal проектом, то можна встановити брикпоінт в дебагер на Drupal.attachBehaviors() і подивитися де і як викликається цей метод.

розуміння

Після того,як сторінка буде перезавантажена, дебагер буде зупинятися і чекати наших дій щоразу, як буде викликаний Drupal.attachBehaviors()

розуміння

Раніше ми сказали, що Drupal буде викликати Drupal.attachBehaviors() після повного завантаження DOM. Давайте перевіримо це у дебагері. Нижче ви можете бачити змінні context і settings на панелі області видимості змінних.

behaviors

Як бачите більшість кастомних behaviors викликаються один раз, і код здається цілком нормальним на даному етапі. Але давайте перевіримо чи це так, і чи залишиться все гаразд після того, як Drupal.attachBehaviors() буде викликаний повторно на сторінці.

Тестуємо behaviors при наступних викликах

Головна сторінка сайту Syfy використовує Views та Views load more для побудови плитки матеріалів. Давайте проскролимо вниз і натиснемо Load More, щоб побачити що відбувається при цьому:

javascript

розуміння

Змінна context містить тільки область, що оновлюється, замість всього HTML документа. І це значний недогляд. Drupal behaviors, які приймають використовують змінну context як другий аргумент у стандартній функції jQuery пошуку елементів DOM, наприклад: $('#some-id', context) , не будуть виконуватися, якщо в області елементів контексту не буде шуканого. Багато хто зовсім не використовує змінну context при роботі з селекторами jQuery – це поширена помилка. Нижче приклад одного behavior, де видно помилковий підхід:

Цей код встановлює слухач на рівні всього документа на подію натискання клавіші Esc, даючи тим самим можливість сховати меню.

розуміння

У чому тут проблема? у коді використовується змінна context , щоб знайти елемент меню $('.nav-flyout', context) , але не використовується ця змінна, коли мивстановлюємо слухач $(document).keyup(function(e) , це означає що слухач буде додаватися щоразу, коли буде виконуватися Drupal behaviors.

Робимо правильні behaviors

Щоб виправити ситуацію вищою, є два варіанти рішень. Давайте розглянемо обидва.

Використання jQuery Once

У цьому випадку буде додано клас remove-modals-processed, після того, як код буде виконано вперше. Наступного разу, коли Drupal.attachBehaviors() буде викликаний, .once() виявить цей клас елемента і пропустить виконання коду.

Використовуємо змінну context в jQuery селекторі

Дуже часто не використання даного підходу може спричинити досить складний дебаг непередбачених помилок у behaviors. Нижче наведено приклад, де ми використовуємо змінну context в селекторах:

Цей підхід простий і ефективний. jQuery знайде об'єкт document всередині змінної context тільки при першому виклик Drupal.attachBehaviors() . Вдруге виконається цей код може тільки в тому випадку, якщо будь-де буде викликатися Drupal.attachBehaviors(document) , по суті ситуація абсурдна, але варто мати це на увазі.

Альтернатива

У даній ситуації ми зовсім ігноруємо Drupal behaviors і просто чекаємо, поки завантажиться DOM:

Цей код буде працювати як потрібно, і якщо вам не потрібний доступ до корисних речей, які нам дає Drupal behaviors, то ви можете також використовувати його. Це нормально.

Висновок