В этом уроке мы произведём интеграцию дизайна для компонентов меню.
Мы создадим на сайте 3 типа меню:
- Верхнее - тип top (файлы с именем .top.menu.php)
- Верхнее 2 и 3 уровня - тип subtop (файлы с именем .subtop.menu.php)
- Нижнее - тип bottom (файлы с именем .bottom.menu.php)
Верхнее меню будет наследоваться из разделов и будет многоуровневым. Нижнее же меню будет обычным одноуровневым меню, лежащим в корне.
Создадим в корне по файлу меню. Это можно сделать через административный раздел:
Тогда диалог создания пунктов меню будет выглядеть так:
Либо создать файл с именем .ТИП_МЕНЮ.menu.php следующего содержания (пример для файла меню типа top:
$aMenuLinks = Array(
Array(
"Home",
"/",
Array(),
Array(),
""
),
Array(
"About",
"/about/",
Array(),
Array(),
""
),
Array(
"Services",
"/services/",
Array(),
Array(),
""
),
Array(
"Collections",
"/collections/",
Array(),
Array(),
""
),
Array(
"Styles",
"/styles/",
Array(),
Array(),
""
),
Array(
"Contacts",
"/contacts/",
Array(),
Array(),
""
)
);
?>
Поскольку для раздела About в макете есть выпадающие пункты в верхнем меню, мы воспользуемся архитектурой 1С-Битрикс и создадим разделы /about/ и /about/profile/, а так же по меню типа "top" в каждом из них (пока мы не будем создавать страниц, только файловую структуру разделов и меню).
Разместим на нашей тестовой странице 1.php компонент меню bitrix:menu и далее будем работать с ним.
Нижнее меню
Начнём с нижнего меню, поскольку оно проще и позволит изучить работу компонента.
Воспользуемся шаблоном .default и зададим для работы компонента меню типа "bottom" (нижнее):
<?$APPLICATION->IncludeComponent("bitrix:menu", ".default", array(
"ROOT_MENU_TYPE" => "bottom", "MENU_CACHE_TYPE" => "N", "MENU_CACHE_TIME" => "3600", "MENU_CACHE_USE_GROUPS" => "Y", "MENU_CACHE_GET_VARS" => array( ), "MAX_LEVEL" => "1", "CHILD_MENU_TYPE" => "left", "USE_EXT" => "N", "DELAY" => "N", "ALLOW_MULTI_SELECT" => "N" ), false );?> |
Скопируем шаблон компонента под именем "bottom" в шаблон сайта:
Хотя это очень лаконичный шаблон, в целях обучения мы не возьмём от него практически ничего:
<?if (!defined("B_PROLOG_INCLUDED") || B_PROLOG_INCLUDED!==true)die();?>
<!--Проверка подключен ли пролог--> <?if (!empty($arResult)):?> <!--в массиве пунктов меню есть элементы--> <?foreach($arResult as $arItem):?> <!--цикл перебора элементов массива пунктов меню--> <a href="<?=$arItem["LINK"]?>"><?=$arItem["TEXT"]?></a> <!--вывод пункта меню--> <?endforeach?> <!--завершение цикла--> <?endif?> |
Теперь воспользуемся волшебной функцией вывода информации из переменной.
<? echo "<pre>"; print_r($arItem); echo "</pre>";?> |
Поставим этот код сразу после начала цикла и сохраним шаблон. Теперь в публичной части мы увидим следующую картину:
Нас интересует 2 параметра:
- [SELECTED]
- [ITEM_INDEX]
Первый параметр не пуст тогда, когда пункт меню соответствует нашему местонахождению в структуре сайта, т.е. ВЫБРАН.
Значит, мы легко можем использовать его для вывода соответствующего стиля:
<?if($arItem["SELECTED"]):?>class="current"<?endif?> |
Второй параметр отражает номер пункта меню в массиве.
Если мы немного схитрим, то сможем использовать его для простановки разделителей.
Легко определить какой пункт меню первый, однако очень непросто выяснить какой последний. Однако можно заметить, что визуально меню отображается одинаково в обоих случаях:
Все пункты меню, кроме последнего содержат разделитель:
<li><a href="URL">Menu Text</a>|</li> |
Все пункты меню, кроме первого содержат разделитель:
<li>|<a href="URL">Menu Text</a></li> |
Мы воспользуемся этой особенностью и слегка подкорректируем вёрстку. Если бы это было невозможно, нам пришлось бы завести счётчик.
Разделитель выведем следующим кодом:
<?if($arItem['ITEM_INDEX'] != 0) :?>|<?endif?> |
Тогда шаблон компонента меню будет выглядеть:
<?if (!defined("B_PROLOG_INCLUDED") || B_PROLOG_INCLUDED!==true)die();?>
<?if (!empty($arResult)):?> <ul class="footer-menu"> <?foreach($arResult as $arItem):?> <li><?if($arItem['ITEM_INDEX'] != 0) :?>|<?endif?><a <?if($arItem["SELECTED"]):?>class="current"<?endif?> href="<?=$arItem["LINK"]?>"><?=$arItem["TEXT"]?></a></li> <?endforeach?> </ul> <?endif?> |
Не забудем удалить лишний мусор в папке шаблона, доставшийся нам в наследство от шаблона .default:
- папка /images/
- style.css
Теперь осталось только разместить вызов компонента нижнего меню вместо статики в шаблоне (не забыв указать тип кеширования, например, автоматическое и достаточно большое время кеширование, ведь нижнее меню мы будем менять редко, поэтому мы поставим 1 сутки, но вы можете поставить своё время или отключить кеширование вовсе):
<?$APPLICATION->IncludeComponent("bitrix:menu", "bottom", array(
"ROOT_MENU_TYPE" => "bottom", "MENU_CACHE_TYPE" => "A", "MENU_CACHE_TIME" => "86400", "MENU_CACHE_USE_GROUPS" => "Y", "MENU_CACHE_GET_VARS" => array( ), "MAX_LEVEL" => "1", "CHILD_MENU_TYPE" => "left", "USE_EXT" => "N", "DELAY" => "N", "ALLOW_MULTI_SELECT" => "N" ), false );?> |
Мы сделали простое и лёгкое меню с подсветкой выбранного раздела сайта и разделителями между пунктами меню!
Верхнее меню
Для разработки меню мы возьмём системный шаблон horizontal_multilevel и скопируем его под названием top в шаблон сайта (как уже было описано ранее для нижнего меню).
В дополнительных настройках компонента меню выберем 3 уровня вложенности меню (для построения выпадающего меню) и нижнее меню в качестве меню для 2 и 3 уровней.
В результате получится:
ПРИМЕЧАНИЕ. Мы могли воспользоваться всего 1 типом меню - верхним. Однако тогда нам пришлось бы при разработке шаблона поставить условие не выводить дочерние пункты для 1 меню (с иконкой в виде домика вместо текста). Это усложнило бы шаблон, хотя возможно и было бы "красивее".
Обратим внимание на 2 новых параметров, характеризующих пункты меню, которые могут нас интересовать:
- [DEPTH_LEVEL] - уровень вложенности
- [IS_PARENT] - есть ли у пункта меню дочерние
Итак, начнём по порядку:
1й пункт меню с иконкой домики при узком разрешении экрана (на мобильных устройствах, например) превращающийся в текст задаётся в макете:
<li class="active li-first"><a href="index.html"><em class="hidden-phone"></em><span class="visible-phone">Home</span></a></li> |
К сожалению, это слишком громоздкая конструкция и она слишком сильно отличается от идущих далее пунктов, поэтому придётся задать его отдельно, поставив условие на ITEM_INDEX=0. Однако стоит помнить, что индекс начинает строиться с 0 для каждого уровня, т.е. помимо индекса следует проверить и DEPTH_LEVEL=1.
Альтернативный путь - задать отдельное свойство для данного пункта меню. Это делается в расширенном режиме редактирования меню:
Зададим пункту меню Home параметр ICON=Y:
Тогда отладочный массив будет содержать этой свойство и по нему можно будет определить нужный нам пункт меню:
Простейшая проверка на наличие значения в переменной ICON будет выглядеть:
<?if (!empty($arItem["PARAMS"]['ICON'])):?>
<!--Переменная НЕ пуста--> <?else:?> <!--Переменная пуста--> <?endif?> |
Мы воспользуемся им до всех остальных действий с меню. Поскольку у нас иконка выводится только для 1 корневого элемента логика будет максимально простой. Однако при желании мы можем передавать в этом параметре, например тип иконки или адрес её картинки, если желаем использовать несколько.
Не забудем поставить класс active в случае если пункт меню соответствует местонахождению в структуре. Тогда этот блок будет выглядеть:
<?if (!empty($arItem["PARAMS"]['ICON'])):?>
<li class="<?if ($arItem["SELECTED"]):?>active <?endif?>li-first"><a href="<?=$arItem["LINK"]?>"><em class="hidden-phone"></em><span class="visible-phone"><?=$arItem["TEXT"]?></span></a></li> <?else:?> ..... <?endif?> |
Теперь обратим внимание на кусок кода, осуществляющий проверку на наличие у пункта меню дочерних по условию <?if ($arItem["IS_PARENT"]):?>. Согласно макету для пунктов меню-родителей мы должны добавить класс class="sub-menu" - он добавит симпатичную стрелочку этим пунктам меню.
Так же не забудем, что начиная с пунктов родителей у нас начинается новый "список", выделяющий следующий уровень меню, который необходимо деактивировать (его активация происходит JS при наведении курсора мыши). Тогда этот блок кода будет выглядеть:
<?if ($arItem["IS_PARENT"]):?>
<?if ($arItem["DEPTH_LEVEL"] == 1):?> <li class="sub-menu <?if ($arItem["SELECTED"]):?> active<?endif?>"><a href="<?=$arItem["LINK"]?>"><?=$arItem["TEXT"]?></a> <ul style="display: none;"> <?else:?> <li class="sub-menu <?if ($arItem["SELECTED"]):?> active<?endif?>"><a href="<?=$arItem["LINK"]?>"><?=$arItem["TEXT"]?></a> <ul style="display: none;"> <?endif?> <?else:?> ........... <?endif?> |
В принципе меню готово и осталось лишь слегка его "причесать".
В частности для устройств с узким экраном верхнее меню "схлопывается" и раскрывается в ответ на нажатие кнопки "Menu". Следует завести параметр в .parameters.php в шаблоне компонента, задающий данный текст:
"TOP_MENU_NAME" => Array(
"NAME" => GetMessage("TOP_MENU_NAME"), "TYPE" => "HTML", "DEFAULT" => "Menu", ), |
Создать для него языковые фразы и вывести в шаблоне компонента:
<a class="btn btn-navbar" data-toggle="collapse" data-target=".nav-collapse_"><?=$arParams["TOP_MENU_NAME"]?></a> |
Обратим лишь внимание на особенность вёрстки - кнопки социальных сервисов, которые мы ранее вынесли во включаемую область находятся внутри блока вёртки меню. А значит их следует внести внутрь шаблона компонента. Можно просто перенести вызов включаемой области внутрь шаблона.
Социальные кнопки
Несмотря на обозначенный ранее простой способ решения задачи мы воспользуемся другим, более интересным решением - вынесем социальные кнопки в параметры компонента верхнего меню.
В качестве дополнительного бонуса мы нарисовали 1 дополнительную иконку для панели социальных кнопок - Github. Надеемся, она вам понравится.
Для этого в шаблоне компонента создадим файл настроек .parameters.php.
Зададим в нём 1й параметр:
$arTemplateParameters = array(
"USE_SOCIAL_ICONS" => Array( "NAME" => GetMessage("USE_SOCIAL_ICONS"), "TYPE" => "CHECKBOX", "MULTIPLE" => "N", "VALUE" => "Y", "DEFAULT" =>"N", "REFRESH"=> "Y", ), ); |
Этот параметр будет использоваться для активации\деактивации панели социальных кнопок. Параметр REFRESH=Y показывает 1С-Битрикс, что необходимо перезагрузить настройки после изменения этого параметра. Таким образом мы можем привязать вывод в настройках компонента остальные параметры к данному (дабы не засорять список потенциально ненужными пунктами).
Теперь зададим остальные параметры:
if ($arCurrentValues["USE_SOCIAL_ICONS"] == "Y") { $arTemplateParameters["SOCIAL_ICONS_TWITTER"] = array( "NAME" => GetMessage("SOCIAL_ICONS_TWITTER"), "TYPE" => "HTML", "DEFAULT" => "", ); $arTemplateParameters["SOCIAL_ICONS_FACEBOOK"] = array( "NAME" => GetMessage("SOCIAL_ICONS_FACEBOOK"), "TYPE" => "HTML", "DEFAULT" => "", ); $arTemplateParameters["SOCIAL_ICONS_GOOGLE_PLUS"] = array( "NAME" => GetMessage("SOCIAL_ICONS_GOOGLE_PLUS"), "TYPE" => "HTML", "DEFAULT" => "", ); $arTemplateParameters["SOCIAL_ICONS_RSS"] = array( "NAME" => GetMessage("SOCIAL_ICONS_RSS"), "TYPE" => "HTML", "DEFAULT" => "", ); $arTemplateParameters["SOCIAL_ICONS_GITHUB"] = array( "NAME" => GetMessage("SOCIAL_ICONS_GITHUB"), "TYPE" => "HTML", "DEFAULT" => "", ); } |
Не забудем создать языковые файлы со всеми фразами для настроек компонента:
- /bitrix/templates/stylish/components/bitrix/menu/top/lang/en/.parameters.php
- /bitrix/templates/stylish/components/bitrix/menu/top/lang/ru/.parameters.php
В результате настройки компонента станут выглядеть так:
Теперь добавим в шаблон компонента код, который будем выводить блок социальных кнопок, если параметр USE_SOCIAL_ICONS=Y, а каждая конкретная строка будет выводиться в случае непустого значения соответствующего параметра:
<?if ($arParams["USE_SOCIAL_ICONS"] == Y):?>
<ul class="social-icons"> <?if (!empty($arParams["SOCIAL_ICONS_TWITTER"])):?><li><a href="<?=$arParams["SOCIAL_ICONS_TWITTER"]?>"><img src="/bitrix/templates/stylish/img/icon-1.png" alt="Twitter"></a></li><?endif?> <?if (!empty($arParams["SOCIAL_ICONS_FACEBOOK"])):?><li><a href="<?=$arParams["SOCIAL_ICONS_FACEBOOK"]?>"><img src="/bitrix/templates/stylish/img/icon-2.png" alt="Facebook"></a></li><?endif?> <?if (!empty($arParams["SOCIAL_ICONS_GOOGLE_PLUS"])):?><li><a href="<?=$arParams["SOCIAL_ICONS_GOOGLE_PLUS"]?>"><img src="/bitrix/templates/stylish/img/icon-3.png" alt="Google+"></a></li><?endif?> <?if (!empty($arParams["SOCIAL_ICONS_RSS"])):?><li><a href="<?=$arParams["SOCIAL_ICONS_RSS"]?>"><img src="/bitrix/templates/stylish/img/icon-4.png" alt="RSS"></a></li><?endif?> <?if (!empty($arParams["SOCIAL_ICONS_GITHUB"])):?><li><a href="<?=$arParams["SOCIAL_ICONS_GITHUB"]?>"><img src="/bitrix/templates/stylish/img/icon-5.png" alt="Github"></a></li><?endif?> </ul> <?endif?> |
Осталось удалить всякий мусор из шаблона (JS, CSS, старые картинки шаблона), переместить в шаблон компонента социальные иконки из шаблона сайта и скорректировать соответствующие пути. Так же теперь можно удалить файл включаемой области с кодом социальных кнопок из шаблона сайта.
Результат работы над верхним меню
Шаблон компонента:
<?if (!defined("B_PROLOG_INCLUDED") || B_PROLOG_INCLUDED!==true)die();?>
<?if (!empty($arResult)):?> <div class="navbar navbar_ clearfix"> <div class="navbar-inner navbar-inner_"> <div class="container"> <a class="btn btn-navbar" data-toggle="collapse" data-target=".nav-collapse_"><?=$arParams["TOP_MENU_NAME"]?></a> <div class="nav-collapse nav-collapse_ collapse"> <ul class="nav sf-menu sf-js-enabled"> <? $previousLevel = 0; foreach($arResult as $arItem):?> <?if ($previousLevel && $arItem["DEPTH_LEVEL"] < $previousLevel):?> <?=str_repeat("</ul></li>", ($previousLevel - $arItem["DEPTH_LEVEL"]));?> <?endif?> <?if (!empty($arItem["PARAMS"]['ICON'])):?> <li class="<?if ($arItem["SELECTED"]):?>active <?endif?>li-first"><a href="<?=$arItem["LINK"]?>"><em class="hidden-phone"></em><span class="visible-phone"><?=$arItem["TEXT"]?></span></a></li> <?else:?> <?if ($arItem["IS_PARENT"]):?> <?if ($arItem["DEPTH_LEVEL"] == 1):?> <li class="sub-menu <?if ($arItem["SELECTED"]):?> active<?endif?>"><a href="<?=$arItem["LINK"]?>"><?=$arItem["TEXT"]?></a> <ul style="display: none;"> <?else:?> <li class="sub-menu <?if ($arItem["SELECTED"]):?> active<?endif?>"><a href="<?=$arItem["LINK"]?>"><?=$arItem["TEXT"]?></a> <ul style="display: none;"> <?endif?> <?else:?> <?if ($arItem["PERMISSION"] > "D"):?> <li<?if ($arItem["SELECTED"]):?> class="active"<?endif?>><a href="<?=$arItem["LINK"]?>"><?=$arItem["TEXT"]?></a></li> <?else:?> <li><a href="" class="denied" title="<?=GetMessage("MENU_ITEM_ACCESS_DENIED")?>"><?=$arItem["TEXT"]?></a></li> <?endif?> <?endif?> <?endif?> <?$previousLevel = $arItem["DEPTH_LEVEL"];?> <?endforeach?> <?if ($previousLevel > 1)://close last item tags?> <?=str_repeat("</ul></li>", ($previousLevel-1) );?> <?endif?> </ul> </div> <?if ($arParams["USE_SOCIAL_ICONS"] == Y):?> <ul class="social-icons"> <?if (!empty($arParams["SOCIAL_ICONS_TWITTER"])):?><li><a href="<?=$arParams["SOCIAL_ICONS_TWITTER"]?>"><img src="<?=SITE_TEMPLATE_PATH?>/components/bitrix/menu/top/images/icon-1.png" alt="Twitter"></a></li><?endif?> <?if (!empty($arParams["SOCIAL_ICONS_FACEBOOK"])):?><li><a href="<?=$arParams["SOCIAL_ICONS_FACEBOOK"]?>"><img src="<?=SITE_TEMPLATE_PATH?>/components/bitrix/menu/top/images/icon-2.png" alt="Facebook"></a></li><?endif?> <?if (!empty($arParams["SOCIAL_ICONS_GOOGLE_PLUS"])):?><li><a href="<?=$arParams["SOCIAL_ICONS_GOOGLE_PLUS"]?>"><img src="<?=SITE_TEMPLATE_PATH?>/components/bitrix/menu/top/images/icon-3.png" alt="Google+"></a></li><?endif?> <?if (!empty($arParams["SOCIAL_ICONS_RSS"])):?><li><a href="<?=$arParams["SOCIAL_ICONS_RSS"]?>"><img src="<?=SITE_TEMPLATE_PATH?>/components/bitrix/menu/top/images/icon-4.png" alt="RSS"></a></li><?endif?> <?if (!empty($arParams["SOCIAL_ICONS_GITHUB"])):?><li><a href="<?=$arParams["SOCIAL_ICONS_GITHUB"]?>"><img src="<?=SITE_TEMPLATE_PATH?>/components/bitrix/menu/top/images/icon-5.png" alt="Github"></a></li><?endif?> </ul> <?endif?> </div> </div> </div> <?endif?> |
Осталось заменить весь верхний навигационный блок (и верхнее меню и социальные кнопки) на вызов компонента верхнего меню (мы специально оставляем 1 из социальных кнопок без адреса):
<?$APPLICATION->IncludeComponent("bitrix:menu", "top", array(
"ROOT_MENU_TYPE" => "top", "MENU_CACHE_TYPE" => "Y", "MENU_CACHE_TIME" => "86400", "MENU_CACHE_USE_GROUPS" => "Y", "MENU_CACHE_GET_VARS" => array( ), "MAX_LEVEL" => "3", "CHILD_MENU_TYPE" => "subtop", "USE_EXT" => "N", "DELAY" => "N", "ALLOW_MULTI_SELECT" => "N", "USE_SOCIAL_ICONS" => "Y", "TOP_MENU_NAME" => "Меню", "SOCIAL_ICONS_TWITTER" => "https://twitter.com/lexnekr", "SOCIAL_ICONS_FACEBOOK" => "", "SOCIAL_ICONS_GOOGLE_PLUS" => "https://plus.google.com/u/0/112316725504958628550/posts", "SOCIAL_ICONS_RSS" => "http://кофедизайн.рф/information/rss/", "SOCIAL_ICONS_GITHUB" => "https://github.com/lexnekr/bitrixtemplate_stylish" ), false );?> |
Не забудьте, что как в верхнем, так и в нижнем меню автор статьи ВКЛЮЧИЛ АВТО КЕШИРОВАНИЕ и задал время хранения кеша равным 1 суткам. Во время работы над сайтом при изменении пунктов меню это может доставить неудобство и потребует вручную обновить кеш (или отключить кеширование в настройках компонента), однако поскольку в меню редко повляются новые пункты во время эксплуатация компонента со включенным кешированием может быть полезна.
Результаты работы данного урока, как всегда можно найти в нашем репозитории на