В статье разберем «по строкам» самый часто используемый шаблон компонента bitrix:menu, который позволяет выводить меню произвольного уровня вложенности.
PHP код шаблона
Ниже приведен полный php-код шаблона horizontal_multilevel с подробными комментариями.
<?if (!defined("B_PROLOG_INCLUDED") || B_PROLOG_INCLUDED!==true)die(); // проверяем, загружена ли служебная часть сайта (ядро)?> <? /* Структура массива $arResult Массив $arResult состоит из вложенных массивов, соответсвующих пунктам меню. Порядок следования пунктов Вложенные массивы содержат ключи: TEXT - текст текущего пункта меню LINK - ссылка текущего пункта меню SELECTED - выбран ли пункт меню в данный момент PERMISSION - доступ на страницу указанную в $LINK, возможны следующие значения: D - доступ запрещён R - чтение (право просмотра содержимого файла) U - документооборот (право на редактирование файла в режиме документооборота) W - запись (право на прямое редактирование) X - полный доступ (право на прямое редактирование файла и право на изменение прав доступа на данных файл) ADDITIONAL_LINKS - дополнительные ссылки для подсветки меню ITEM_TYPE - "D" - директория (если LINK заканчивается на "/"), иначе "P" - страница ITEM_INDEX - порядковый номер пункта меню PARAMS - параметры пунктов меню DEPTH_LEVEL - уровень вложенности пункта меню (1 для главного, 2 и далее для вложенных) IS_PARENT - флаг того, что у этого пункта меню будет подменю Вывод производится вложенными списками вида <ul id="horizontal-multilevel-menu"> <li><a>Пункт первого уровня вложенности</a></li> <li><a>Пункт первого уровня вложенности</a> <ul> <li><a>Пункт второго уровня вложенности</a></li> <li><a>Пункт второго уровня вложенности</a></li> </ul> </li> <li><a>Пункт первого уровня вложенности</a></li> </ul> */ ?> <?if (!empty($arResult)): // если есть хотя бы 1 пункт меню, можно начинать вывод?> <ul id="horizontal-multilevel-menu"> <? $previousLevel = 0; // переменная содержит значение DEPTH_LEVEL предыдущего пункта foreach($arResult as $arItem): // пробегаем по пунктам, $arItem - массив с информацией о текущем пункте?> <?if ($previousLevel && $arItem["DEPTH_LEVEL"] < $previousLevel):?> <?// если уровень вложенности текущего пункта меню меньше чем у предыдущего, значит "подменю" закончилось и нужно закрыть список?> <?=str_repeat("</ul></li>", ($previousLevel - $arItem["DEPTH_LEVEL"]));?> <?endif?> <?if ($arItem["IS_PARENT"]): //если пункт содержит подменю, выводим ссылку и начинаем новый список (тег <ul>)?> <?if ($arItem["DEPTH_LEVEL"] == 1): // если уровень вложенности =1, т.е. это главное меню?> <?// выводим ссылку и добавляем класс "root-item" если пункт неактивный и "root-item-selected" если активный?> <li><a href="<?=$arItem["LINK"]?>" class="<?if ($arItem["SELECTED"]):?>root-item-selected<?else:?>root-item<?endif?>"><?=$arItem["TEXT"]?></a> <ul> <?else: // для остальных уровней вложенности?> <?// выводим ссылку и добавляем класс "parent". Если пункт активный, для элемента списка <li> добавляем класс "item-selected"?> <li<?if ($arItem["SELECTED"]):?> class="item-selected"<?endif?>><a href="<?=$arItem["LINK"]?>" class="parent"><?=$arItem["TEXT"]?></a> <ul> <?endif?> <?else: // для пунктов, не содержащих подменю?> <?if ($arItem["PERMISSION"] > "D"): // проверяем право доступа к пункту?> <?if ($arItem["DEPTH_LEVEL"] == 1): // если уровень вложенности =1, т.е. это главное меню?> <?// выводим ссылку и добавляем класс "root-item" если пункт неактивный и "root-item-selected" если активный?> <li><a href="<?=$arItem["LINK"]?>" class="<?if ($arItem["SELECTED"]):?>root-item-selected<?else:?>root-item<?endif?>"><?=$arItem["TEXT"]?></a></li> <?else: // для остальных уровней вложенности?> <?// выводим ссылку. Если пункт активный, для элемента списка <li> добавляем класс "item-selected"?> <li<?if ($arItem["SELECTED"]):?> class="item-selected"<?endif?>><a href="<?=$arItem["LINK"]?>"><?=$arItem["TEXT"]?></a></li> <?endif?> <?else: // для пунктов, к которым запрещен доступ?> <?if ($arItem["DEPTH_LEVEL"] == 1): // если уровень вложенности =1, т.е. это главное меню?> <?// выводим пустую ссылку и добавляем класс "root-item" если пункт неактивный и "root-item-selected" если активный?> <li><a href="" class="<?if ($arItem["SELECTED"]):?>root-item-selected<?else:?>root-item<?endif?>" title="<?=GetMessage("MENU_ITEM_ACCESS_DENIED")?>"><?=$arItem["TEXT"]?></a></li> <?else: // для остальных уровней вложенности?> <?// выводим пустую ссылку и добавляем класс "denied"?> <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):// если работа завершилась на пункте меню с уровнем вложенности >1, закрываем вложенные списки?> <?=str_repeat("</ul></li>", ($previousLevel-1) );?> <?endif?> </ul> <div class="menu-clear-left"></div> <?endif?>
CSS код шаблона
Кратко пробежимся по css-файлу и выясним, какие правила за что отвечают при визуальном оформлении меню.
/* в соответствии со структурой меню, описанной в template.php контейнер пунтов меню - <ul> контейнер пункта меню - <li> ссылка пункта меню - <a> */ /**Top menu**/ #horizontal-multilevel-menu,#horizontal-multilevel-menu ul /* стили для контейнера пунтов главного и вложенных меню */ #horizontal-multilevel-menu /* стили для контейнера пунктов главного меню */ /*Links*/ #horizontal-multilevel-menu a /* стили для ссылок пунктов меню всех уровней */ #horizontal-multilevel-menu li /* стили для контейнера пункта меню */ /*Root items*/ #horizontal-multilevel-menu li a.root-item /* стили для ссылок главного меню */ /*Root menu selected*/ #horizontal-multilevel-menu li a.root-item-selected /* стили для активной (выделенной) ссылки главного меню */ /*Root items: hover*/ #horizontal-multilevel-menu li:hover a.root-item, #horizontal-multilevel-menu li.jshover a.root-item /* стили для ссылок главного меню при наведении мышью */ /*Item-parents*/ #horizontal-multilevel-menu a.parent /* стили для ссылок НЕглавного меню, у которых есть вложенное меню */ /*Denied items*/ #horizontal-multilevel-menu a.denied /* стили для ссылок, к которым запрещен доступ */ /*Child-items: hover*/ #horizontal-multilevel-menu li:hover, #horizontal-multilevel-menu li.jshover /* стили для для контейнера пункта меню при наведении мышью */ /*Child-items selected*/ #horizontal-multilevel-menu li.item-selected /* стили для контейнера активного (выделенного) пункта вложенного меню */ /*Sub-menu box*/ #horizontal-multilevel-menu li ul /* стили для контейнера пунктов вложенного меню */ /*Sub-menu item box*/ #horizontal-multilevel-menu li li /* стили для контейнера пункта вложенного меню */ /*Item link*/ #horizontal-multilevel-menu li ul a /* стили для ссылки пункта вложенного меню */ /*Items text color & size */ #horizontal-multilevel-menu li a, #horizontal-multilevel-menu li:hover li a, #horizontal-multilevel-menu li.jshover li a, #horizontal-multilevel-menu li:hover li:hover li a, #horizontal-multilevel-menu li.jshover li.jshover li a, #horizontal-multilevel-menu li:hover li:hover li:hover li a, #horizontal-multilevel-menu li.jshover li.jshover li.jshover li a, #horizontal-multilevel-menu li:hover li:hover li:hover li:hover li a, #horizontal-multilevel-menu li.jshover li.jshover li.jshover li.jshover li a, #horizontal-multilevel-menu li:hover li:hover li:hover li:hover li:hover li a, #horizontal-multilevel-menu li.jshover li.jshover li.jshover li.jshover li.jshover li a /* стили для ссылок вложенного меню */ /*Items text color & size: hover*/ #horizontal-multilevel-menu li:hover li:hover a, #horizontal-multilevel-menu li.jshover li.jshover a, #horizontal-multilevel-menu li:hover li:hover li:hover a, #horizontal-multilevel-menu li.jshover li.jshover li.jshover a, #horizontal-multilevel-menu li:hover li:hover li:hover li:hover a, #horizontal-multilevel-menu li.jshover li.jshover li.jshover li.jshover a #horizontal-multilevel-menu li:hover li:hover li:hover li:hover li:hover a, #horizontal-multilevel-menu li.jshover li.jshover li.jshover li.jshover li.jshover a #horizontal-multilevel-menu li:hover li:hover li:hover li:hover li:hover li:hover a, #horizontal-multilevel-menu li.jshover li.jshover li.jshover li.jshover li.jshover li.jshover a /* стили для ссылок вложенного меню при наведении мышью */ #horizontal-multilevel-menu li ul ul /* стили для контейнера пунктов вложенного меню (уровень вложенности >2) */ #horizontal-multilevel-menu li:hover ul ul, #horizontal-multilevel-menu li.jshover ul ul, #horizontal-multilevel-menu li:hover ul ul ul, #horizontal-multilevel-menu li.jshover ul ul ul, #horizontal-multilevel-menu li:hover ul ul ul ul, #horizontal-multilevel-menu li.jshover ul ul ul ul, #horizontal-multilevel-menu li:hover ul ul ul ul ul, #horizontal-multilevel-menu li.jshover ul ul ul ul ul /* обработка реакции на наведение мышью - скрываем вложенные меню уровня, более чем на 1 превышающее выделенный */ #horizontal-multilevel-menu li:hover ul, #horizontal-multilevel-menu li.jshover ul, #horizontal-multilevel-menu li li:hover ul, #horizontal-multilevel-menu li li.jshover ul, #horizontal-multilevel-menu li li li:hover ul, #horizontal-multilevel-menu li li li.jshover ul, #horizontal-multilevel-menu li li li li:hover ul, #horizontal-multilevel-menu li li li li.jshover ul, #horizontal-multilevel-menu li li li li li:hover ul, #horizontal-multilevel-menu li li li li li.jshover ul /* обработка реакции на наведение мышью, показываем вложенные меню */
JS файл шаблона
Этот скрипт существует с одной единственной целью — научить браузер Internet Explorer версии 6 и ниже «понимать» наведение мышью на тег <li>. При наведении элементу присваивается класс «jshover», после «ухода» курсора за пределы элемента — класс снимается.
Заключение
Стандартный шаблон horizontal_multilevel довольно гибкий и позволяет реализовать различные вариации меню правкой только файла стилей. Однако, некоторые необходимые вещи не реализованы — количество пунктов меню n-го уровня можно узнать только полным перебором массива-результата. Еще более сложной задачей является «выделение» в цикле последнего пункта подменю, например, для выделения скругленной рамкой.
Пишите свои вопросы в комментариях, я буду делиться своими наработками конкретно к Вашей задаче.
PS: небольшой привет разработчикам. Этот баг повторяется очень часто при установке продукта из Opera
Больше статей и материалов по web-разработке в tg-канале - подписывайтесь!
Подписаться в telegram
Статья — просто must have для таких нубов в Битриксе, как я! А откуда он тянет $arResult?
$arResult передается из компонента как результат его работы
Алексей! Вот столкнулся с задачей вывода последнего пункта меню в отличном от остальных стиле, подскажите пожалуйста как решить эту проблему.
Андрей, нужно пробежать по всем пунктам и запомнить последний (на нужном уровне). Потом при выводе найти его и выделить:)
Подскажте никак не могу разобраться, как сделать так чтобы вложенность была всего 2.
Тоесть главное меню и их подпапки. больше ничего не надо.
Игорь, вложенность можно задать в настройках компонента
Баг с установкой не только в опере часто встречается. При установке с мака (FF 6.0.2 Chrome Safari 5.1.1) эта ошибка с завидной регулярностью возникает на 75% установки каталога. На Lione’е можно пару раз тыкнуть «Повторить» и поставится, на Snow Leopard’е виснет наглухо.
Тоже новичок ещё в Битриксе. Хочу разобраться с другим типом меню как tree. Можно будет также увидеть разбор этого шаблона. Хотелось бы дописать в него ряд дополнений, но пока разбираюсь ещё только как программировать шаблон.
пишу его для сайта http://medfarma.net. В css я уже немного поправил.
я тоже новичок в Битриксе. Из Vertical_multilevel или Default можно сделат Аккордион меню?
Almat, можно. Из default легче, но одноуровневое, из vertical-multilevel чуть сложнее, но произвольного уровня вложенности.
я видел вашем интернет магазине http://www.autoleon.ru/ левый аккордион меню. Подскажи какой битриксовый шаблон ты там использовал или костомизировал??
заранее благодарю!
Это не меню, а сильно измененный catalog.section.list
я могу сделать типа такого http://dobrovoi.ru/files/accordeon1/index.html с помощью vertical-multilevel?? Я делаю интернет магазин чуть-чуть не хватает функционал и дизайн.
Можно ли сделать из этого меню, что нибудь типа вот такого http://radar-groupe.ru? Этот полностью на HTML. Хочу перетащить его под битрикс но вот сомневаюсь насёт меню. А у VW жосткие стандарты (всё по бренд-буку) и не шагу в сторону.
Михаил, можно, только чуть сложнее с выводом.
А не подскажешь как делают, чтобы на странице отображалось два верхних горизонтальных меню одновременно (то есть меню и подменю)? Пример http://www.ursu.ru
Какой шаблон используют?
Обычно ведь при нажатии кнопки меню, выходит подменю, а меню пропадает.
phisey, нужно модифицировать шаблон компонента меню. Примерно так: определяем активный пункт меню первого уровня — запоминаем его подпункты (отмечая активный, если он есть). Проходим по меню и выводим в строку 1й уровень, затем запомненные подпункты 2й строкой.
Алексей, Здравствуйте!
Понимаю что статья полезная, но к сожалению плохо знаком с PHP, с Битриксом связался буквально пару дней назад, стоит задача сделать всплывающее меню.
Но у меня ничего не выходит, чесно сказать удивлен что такая простейшая вещь требует дополнительных телодвижений.
Запутался окончательно. Не могли бы вы подсказать пошагово как его реализовать?
Дефолтный шаблон horizontal_multilevel уже содержит механизм «выпадания» меню 2го и более уровней. Ничего дополнительно в большинстве случаев делать не нужно, только стилизовать с помощью css
В настройках компонента максимальный уровень вложенности — 4, а мне надо 5, как поправить?
Можно попробовать руками поставить нужную цифру в режиме редактирования страницы как php. Но меню строится где-то в недрах битрикса, поэтому не факт что сработает.
Алексей, добрый день, подскажите плиз, а как сделать (куда именно прописать в шаблоне компонента) меню двухколоночное, т.е. при наведении на пункт меню, выпадает не один столбец а два или больше (как на сайте eldorado.ru например). Спасибо!
Добрый день, как сделать неактивными первый пункт меню?
Mike, с ходу могу предложить 2 варианта:
1. В шаблоне компонента сделать счетчик и по его значению деативировать пункт.
2. В расширенном режиме редактирования меню ввести параметр и по его значению в шаблоне меню деактивировать нужные пункты.
подменю получается слишком длинным, хочу сделать в 2 колонки подскажи как это сделать
Алексей приведите пример «сделать счетчик и по его значению деативировать пункт». Просто много вариантов перепробовал, они не работают + счет ведется во всех меню (не могу сделать сброс когда переходим в след пункт меню, и например число шесть это 3 пункта предыдущего меню + 3 текущего)
$index = $arItem[«DEPTH_LEVEL»];
$count[$index]++;
$count[1] — счётчик меню первого уровня вложенности
$count[2] — счётчик меню второго уровня вложенности
Читал битриксовский меню-туториал (официальный мануал, между прочим) про изменение шиблона и стилей и ничего не понял, как подправить шаблон, чтобы вложенные меню не «съезжали» и перенос нормально работал. Может я тупой? :)
Прочет CSS код шаблона в этой статье и понял ВСЕ! Автору респект!
Здравствуйте. большое спасибо за такую подробную и понятную статью. я бы хотел кое что уточнить что относится не совсем к шаблону. просто я не могу разобраться почему так и как это исправить. проблема в следующем:
у меня в меню ссылки расписаны по примеру:
главная=»/ru/»
первая ссылка меню=»/ru/first/»
вторая ссылка меню=»/ru/second» и т.д. и при этом у меня не зависимо от расположения в данный момент, ссылка главная остаётся активной. то есть если я нажму на 2 или 3 ссылку, будет активна она и главная. страница при этом открывается по нажато ссылке. подскажите как исправить такую вещь?
Можно не отвечать. справился. в вызове компонента есть пункт отвечающий за мультивыделение ссылок — отключил его и всё норм.
Алексей, здравствуйте!
Очень понравилась Ваша статья с комментариями к коду, спасибо за такое детальное описание.
Подскажите, пожалуйста, решение задачи: у меня 2-хуровневное меню. В 1-м уровне последний пункт должен иметь свой стиль. Я прописала код:
$aItem ): ?>
…
<a href="»> //стиль для последнего пункта
<a href="»> //стиль для пунктов, кроме последнего
…
но условие не работает. Подскажите, пожалуйста, как применить стиль?
К предыдущему сообщению:
Я прописала код:
foreach( $arResult as $key => $aItem )
…
if ($arItem[DEPTH_LEVEL] == 1)
if( $key == (count($arResult)- 1))
TEXT //стиль для последнего пункта
else
TEXT> //стиль для пунктов, кроме последнего
endif
…
но условие не работает. Подскажите, пожалуйста, как применить стиль?
огромное спасибо! все разжовано как надо!
Здравствуйте, подскажите как уже созданную страницу добавить в выпадающий список? есть куча созданных страниц, надо их прикрепить к меню (меню изначально было написано в html и указывало на страницы ) теперь надо все страницы прикрепить к горизонтальному меню, сколько пробую никак не получается, при выборе пункта добавить в меню — предлагает верхнее, левое или нижнее. Мне надо добавить некоторые страницы в верхний уровень, а большинство в выпадающий. Как это сделать?
Большое спасибо за комментарии к коду! Очень помогло!
Отлично разжевано, теперь все четко и ясно. Спасибо:)
Спасибо Алексей Валеев за статью. Комментарии к коду позволили в сжатые сроки сделать свое меню.
В приведенном коде имеется ошибка: для пунктов меню, у которых установлен IS_PARENT, права доступа не проверяются.
В самом деле Не чего не понятно!
Доброво времени суток.
Я новичок.
Подскажите где ошибка.
<li class=»dropdown active» ><a href="» class=»dropdown-toggle» data-toggle=»dropdown» data-hover=»dropdown» data-delay=»0″ data-close-others=»false»>
<li class=»dropdown active» ><a href="» class=»dropdown-toggle» data-toggle=»dropdown» data-hover=»dropdown» data-delay=»0″ data-close-others=»false»>
Где ошибка???
Не возвращается ссылка LINK
а как можно сделать .current для самой первой, главной кнопки top меню битрикс шаблона ?
мне нужно создать такое меню
http://jemand.ru/examples/vertikalnoe-vypadayushhee-menyu-cssjs-onclick.html#
но что-то я не могу разобраться что куда.
помогите.
А про шаблоны компонентов как catalog.section.list и catalog.list такое будет? Очень бы хотелось
Здравствуйте Алексей!
Я делаю меню из catalog.section.list, как можно сделать чтоб подсвечивался активный раздел по аналогии $arItem[«SELECTED»], и как сделать проверку на родителя по аналогии $arIrem[«IS_PARENT»]. Подскажите пожалуйста если вас не затруднит!