Введение
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.