Введение

Magento 2 использует библиотеку jQuery в качестве основы для интерактивных JS-компонентов во frontend-части магазина. Количество разработанных решений довольно обширное, но все же, часто у разработчиков возникает потребность изменять поведение тех или иных компонентов. Данная статья посвящена основам разработки и расширении jQuery widgets в том контексте, в котором нам преподносит его Magento 2.

Типовая постановка задачи

Давайте рассмотрим пример. Представьте что вам на текущем этапе проекта необходимо стилизовать footer, в котором содержатся основные ссылки магазина. Ниже на скриншоте показан один из примеров, у нас могут содержаться сгруппированные в колонки ссылки, колонок может быть произвольное количество. Под цифрой 1 обозначены условные заголовки группы ссылок, сами ссылки обозначены цифрой 2

Десктопный, планшетный виды

В мобильной версии дизайна требуется следующий вид:

Мобильный вид

В desktop/tablet версиях дизайна никакой интерактивности к ссылкам применять не нужно, а в mobile версии ссылки скрываются/показываются при нажатии на заголовок.

Если обратиться к официальной документации Magento для frontend-разработчиков (Источник №1) то можно увидеть подходящий для нашего случая компонент Accordion (Источник №2). Специфика нашего дизайна в том что компонент должен активироваться только в мобильной версии, но в компоненте Accordion подходящих опций для задания breakpoints нет. Тем самым у нас возникает потребность в расширении функциональности стандартного Accordion. Мы добавим виджету возможность инициализироваться и уничтожаться в зависимости от заданных breakpoints.

Расширение виджета

Создадим файл:

app/design/frontend/{vendor}/{theme}/web/js/destroyableAccordion.js

расширяющий логику стандартного accordion, который располагается по следующему пути:

lib/web/mage/accordion.js 

Зарегистрируем наш файл в конфигурации requirejs, для этого создадим файл:

app/design/frontend/{vendor}/{theme}/requirejs-config.js

И запишем следующее содержимое:

var config = {
    map: {
        "*": {
            "destroyableAccordion": "js/destroyableAccordion"
        }
    }
};

На данном шаге мы добились того что создали алиас “destroyableAccordion” для нашего виджета, по которому можем инициализировать виджет или подключать его в более комплексных компонентах.

Запишем в destroyableAccordion следующее содержимое:

define([
    'jquery',
    'matchMedia',
    'mage/accordion'
], function($ , mediaCheck){
    $.widget(namespace.destroyableAccordion, $.mage.accordion, {
        options: {     
            mediaType: null,
            breakpoint: null
        },
        _create : function () {
            this._super();
            this._destroyOn();
        },
        _destroyOn : function(){
            var breakPoint = this.options.breakpoint;
            var mediaType = this.options.mediaType;
            mediaCheck({
                media: '(' + mediaType + ': ' + breakPoint + 'px)',
                entry: $.proxy(function() {
                    this._destroy();
                    $.each(this.contents, function() {
                        $(this).show();
                    });
                }, this),
                exit: $.proxy(function() {
                    this._processPanels();
                }, this)
            });
        }
    });
    return $.namespace.destroyableAccordion;
});

Рассмотрим вышепредставленный код:

С 1 по 5 строки - с помощью requirejs осуществляется импорт jQuery, библиотеки для работы с медиа-запросами matchMedia, и расширяемый mage/accordion.

6 строка - вызывается функция widget из jQuery, которая в нашем случае принимает три параметра:

  • строку с названием нашего компонента с указанным namespace
  • объект расширяемого виджета
  • объект содержащий опции и расширяющие стандартную функциональность методы

С 7 по 10 строки - список опций, необходимых для передачи в функции destroyOn. Описывать опции в файле виджета с пустыми значениями не обязательно, достаточно передать их при инициализации, здесь опции перечислены исключительно для наглядности.

С 11 по 14 строки - функция _create() является конструктором и вызывается при создании виджета, this в этой функции - непосредственно инстанс виджета. В этой функции мы вызываем _create у расширяемого mage.accordion через вызов функции this._super(). И далее вызываем метод нашей функциональности this._destroyOn();

С 15 по 29 строки - описан метод _destroyOn(), в котором склеиваются переданные опции в строку медиазапроса, которая в дальнейшем используется в качестве аргумента для mediaCheck. При ресайзе браузера если разрешение экрана соответствует медиазапросу то вызывается метод this.destroy() у виджета, иначе this._processPanels(). Последняя функция описана в mage.tabs и содержит в себе логику кликов на табы для раскрытия целевого контента.

Теперь мы готовы инициализировать наш виджет через специальный атрибут Magento 2 data-mage-init (дополнительную информацию по способам инициализации JS-кода вы можете найти в источнике №3), ниже показан пример:

<ul class="footer-links_accordion" data-mage-init='{"destroyableAccordion":{"mediaType": "min-width","breakpoint": "768"}}'>
	<li class="footer-links_accordion_item" role="tablist">
		<div class="footer-links_accordion_item_title" data-role="collapsible" role="tab">
			<div data-role="trigger"><span>Here to help</span></div>
		</div>
		<div class="footer-links_accordion_item_content" data-role="content" role="tabpanel">
			<ul class="footer-list">
				<li class="footer-list_item"><a href="#">My account</a></li>
			</ul>
		</div>
	</li>
</ul>

Таким образом мы рассмотрели простейшие и самые лучшие техники по расширению JS-логики стандартных виджетов в Magento 2. Хорошим тоном является организация всех JS-файлов проекта в отдельных файлах, их дальнейший импорт через requirejs и использование декларативного подхода в инициализации JS.

Источники

  1. Официальная документации Magento для frontend-разработчиков
  2. Magento 2 Accordion widget
  3. Способы инициализации JS-кода