8.8. Работа с javascript/jQuery в Drupal 8. Что такое behaviors?

Главные вкладки

levmyshkin 6 августа 2019 в 13:29

Для начала давайте вернемся к тому как подключать кастомные javascript файлы к нашей теме. В файле .libraries.yml нужно подключить js:

global-styling:
  version: 1.x
  css:
    theme:
      css/style.css: {}
      css/print.css: { media: print }
  js:
    js/custom.js: {}
  dependencies:
    - core/jquery
    - core/jquery.once

Важно соблюдать отступы, чтобы он был в два пробела. Итак, мы подключили файл js/custom.js. Но этого не достаточно чтобы у нас работал jQuery. Дело в том что ядро друпала не требует jQuery и jQuery не подключается. Его нужно подключать отдельно:

dependencies:
  - core/jquery

Также мы будем использовать jQuery.once(), это отдельный плагин для jQuery, для того чтобы навешивать события и методы на селектор только однажды.

dependencies:
  - core/jquery
  - core/jquery.once

Дело в том, что мы будем писать код javascript, который будет вызывать друпалом несколько раз по разным событиям. Поэтому нам будет нужен этот метод .once().

Теперь давайте добавим немного кода в файл custom.js:

(function ($) {
  Drupal.behaviors.myModuleBehavior = {
    attach: function (context, settings) {
      $(context).find('.click-me').once('myCustomBehavior').click(function () {
        alert('Hello, World!');
      });
    }
  };
})(jQuery);

Давайте разберем по порядку, что это все значит.

(function ($) {
 
})(jQuery);

Мы оборачиваем код jQuery в такую конструкцию, потому что jQuery в друпале запускается в режиме .noConflict(). Это нужно для того чтобы использовать знак доллара $, и это не конфликтовало с другими javascript фреймворками Prototype, MooTools. Вряд ли вам придется встретиться с этими фреймворками, jQuery плотно занял лидирующие позиции. Но в эту конструкцию вам придется оборачивать весь jQuery-код.

(function ($) {
  Drupal.behaviors.myModuleBehavior = {
    attach: function (context, settings) {
 
    }
  };
})(jQuery);

Вот мы и подошли к behavior'ам. Если вы пишите jQuery код в друпале, вам нужно его во-первых обернуть в function($), а во-вторых в behavior. Имя behavior'а должно быть уникальным, у нас в примере myModuleBehavior, но вам нужно для каждого behavior писать свое имя:

(function ($) {
  Drupal.behaviors.myModuleBehavior = {
    attach: function (context, settings) {
 
    }
  };
 
  Drupal.behaviors.productPageBehavior = {
    attach: function (context, settings) {
 
    }
  };
})(jQuery);

Используйте camelCase для наименования behavior'ов. Behavior вызывается при загрузке страницы, на каждый AJAX-запрос. Таким образом, когда на сайт подгружается новый контент и встраивается в структуру существующего сайта, то вызывается код из behavior, каждый раз. Это значительно отличается от конструкции:

$(document).ready(function () {
  // Do some fancy stuff.
  // Не используйте такой код в Drupal 8 (да и в Drupal 7 тоже).
});

которая вызывается только один раз при загрузке странице.

Если вы начали использовать behavior'ы и заметили, что у вас происходят странные события с сайтом, например через jQuery блок добавляется несколько раз:

(function ($) {
  Drupal.behaviors.myModuleBehavior = {
    attach: function (context, settings) {
      // Behavior вызывается несколько раз на странице, не забывайте использовать функцию .once().
      $('.inner').append('<p>Test</p>');
    }
  };
})(jQuery);

При каждом ajax-запросе у вас будет добавлять еще один параграф Test. Поэтому нужно добавить функцию .once():

(function ($) {
  Drupal.behaviors.myModuleBehavior = {
    attach: function (context, settings) {
      // Behavior вызывается несколько раз на странице, не забывайте использовать функцию .once().
      $('.inner').once('add-paragraph').append('<p>Test</p>');
    }
  };
})(jQuery);

Еще одна фича behavior это переменная context. Каждый раз когда на сайт добавляется новый контент при загрузке страницы или через ajax, то весь новый контент находится в переменной context. Таким образом нам не нужно проходить все DOM дерево, после каждого ajax запроса, чтобы навесить событие на селектор. Достаточно пройтись только по context'у:

(function ($) {
  Drupal.behaviors.myModuleBehavior = {
    attach: function (context, settings) {
      // Behavior вызывается несколько раз на странице, не забывайте использовать функцию .once().
      $(context).find('.inner').once('add-paragraph').append('<p>Test</p>');
    }
  };
})(jQuery);

Теперь добавление параграфа написано в правильном друпал стиле. Конечно, вы можете использовать старую запись с document.ready(), но тогда это будет работать только один раз и медленнее чем через behavior'ы.

Если у вас возникнут вопросы по jQuery/javascript или предложения по дополнительным темам пишите в комментариях.

Комментарии

Аватар пользователя new-art21 new-art21 22 октября 2020 в 12:34

Столкнулась с проблемой jquery
Хотела сделать адаптивное меню из двух меню, по урокам сделала на js с использованием jquery-3.4.1.slim.min.js
Но этот скрипт конфликтует со скриптами встоенными.
И тут Ваша статья! она супер! Просто обернуть код