В статье разберем «по строкам» самый часто используемый шаблон компонента 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

44 комментария “Новичкам — разбираемся с шаблоном меню horizontal_multilevel

  1. Ксения

    Статья — просто must have для таких нубов в Битриксе, как я! А откуда он тянет $arResult?

  2. Андрей

    Алексей! Вот столкнулся с задачей вывода последнего пункта меню в отличном от остальных стиле, подскажите пожалуйста как решить эту проблему.

  3. Алексей Валеев

    Андрей, нужно пробежать по всем пунктам и запомнить последний (на нужном уровне). Потом при выводе найти его и выделить:)

  4. Игорь

    Подскажте никак не могу разобраться, как сделать так чтобы вложенность была всего 2.
    Тоесть главное меню и их подпапки. больше ничего не надо.

  5. siriusianin

    Баг с установкой не только в опере часто встречается. При установке с мака (FF 6.0.2 Chrome Safari 5.1.1) эта ошибка с завидной регулярностью возникает на 75% установки каталога. На Lione’е можно пару раз тыкнуть «Повторить» и поставится, на Snow Leopard’е виснет наглухо.

  6. Антон Парфенов

    Тоже новичок ещё в Битриксе. Хочу разобраться с другим типом меню как tree. Можно будет также увидеть разбор этого шаблона. Хотелось бы дописать в него ряд дополнений, но пока разбираюсь ещё только как программировать шаблон.
    пишу его для сайта http://medfarma.net. В css я уже немного поправил.

  7. Almat

    я тоже новичок в Битриксе. Из Vertical_multilevel или Default можно сделат Аккордион меню?

  8. Алексей Валеев

    Almat, можно. Из default легче, но одноуровневое, из vertical-multilevel чуть сложнее, но произвольного уровня вложенности.

  9. Almat

    я видел вашем интернет магазине http://www.autoleon.ru/ левый аккордион меню. Подскажи какой битриксовый шаблон ты там использовал или костомизировал??
    заранее благодарю!

  10. Михаил

    Можно ли сделать из этого меню, что нибудь типа вот такого http://radar-groupe.ru? Этот полностью на HTML. Хочу перетащить его под битрикс но вот сомневаюсь насёт меню. А у VW жосткие стандарты (всё по бренд-буку) и не шагу в сторону.

  11. phisey

    А не подскажешь как делают, чтобы на странице отображалось два верхних горизонтальных меню одновременно (то есть меню и подменю)? Пример http://www.ursu.ru
    Какой шаблон используют?
    Обычно ведь при нажатии кнопки меню, выходит подменю, а меню пропадает.

  12. Алексей Валеев

    phisey, нужно модифицировать шаблон компонента меню. Примерно так: определяем активный пункт меню первого уровня — запоминаем его подпункты (отмечая активный, если он есть). Проходим по меню и выводим в строку 1й уровень, затем запомненные подпункты 2й строкой.

  13. Андрей

    Алексей, Здравствуйте!
    Понимаю что статья полезная, но к сожалению плохо знаком с PHP, с Битриксом связался буквально пару дней назад, стоит задача сделать всплывающее меню.
    Но у меня ничего не выходит, чесно сказать удивлен что такая простейшая вещь требует дополнительных телодвижений.
    Запутался окончательно. Не могли бы вы подсказать пошагово как его реализовать?

  14. Алексей Валеев Автор записи

    Дефолтный шаблон horizontal_multilevel уже содержит механизм «выпадания» меню 2го и более уровней. Ничего дополнительно в большинстве случаев делать не нужно, только стилизовать с помощью css

  15. Vladimir

    В настройках компонента максимальный уровень вложенности — 4, а мне надо 5, как поправить?

  16. Алексей Валеев

    Можно попробовать руками поставить нужную цифру в режиме редактирования страницы как php. Но меню строится где-то в недрах битрикса, поэтому не факт что сработает.

  17. Сергей

    Алексей, добрый день, подскажите плиз, а как сделать (куда именно прописать в шаблоне компонента) меню двухколоночное, т.е. при наведении на пункт меню, выпадает не один столбец а два или больше (как на сайте eldorado.ru например). Спасибо!

  18. Mike

    Добрый день, как сделать неактивными первый пункт меню?

  19. Алексей Валеев

    Mike, с ходу могу предложить 2 варианта:
    1. В шаблоне компонента сделать счетчик и по его значению деативировать пункт.
    2. В расширенном режиме редактирования меню ввести параметр и по его значению в шаблоне меню деактивировать нужные пункты.

  20. Андрей

    подменю получается слишком длинным, хочу сделать в 2 колонки подскажи как это сделать

  21. Андрей

    Алексей приведите пример «сделать счетчик и по его значению деативировать пункт». Просто много вариантов перепробовал, они не работают + счет ведется во всех меню (не могу сделать сброс когда переходим в след пункт меню, и например число шесть это 3 пункта предыдущего меню + 3 текущего)

  22. Артём

    $index = $arItem[«DEPTH_LEVEL»];
    $count[$index]++;

    $count[1] — счётчик меню первого уровня вложенности
    $count[2] — счётчик меню второго уровня вложенности

  23. RodionFS

    Читал битриксовский меню-туториал (официальный мануал, между прочим) про изменение шиблона и стилей и ничего не понял, как подправить шаблон, чтобы вложенные меню не «съезжали» и перенос нормально работал. Может я тупой? :)
    Прочет CSS код шаблона в этой статье и понял ВСЕ! Автору респект!

  24. Itachi261092

    Здравствуйте. большое спасибо за такую подробную и понятную статью. я бы хотел кое что уточнить что относится не совсем к шаблону. просто я не могу разобраться почему так и как это исправить. проблема в следующем:
    у меня в меню ссылки расписаны по примеру:
    главная=»/ru/»
    первая ссылка меню=»/ru/first/»
    вторая ссылка меню=»/ru/second» и т.д. и при этом у меня не зависимо от расположения в данный момент, ссылка главная остаётся активной. то есть если я нажму на 2 или 3 ссылку, будет активна она и главная. страница при этом открывается по нажато ссылке. подскажите как исправить такую вещь?

  25. Itachi261092

    Можно не отвечать. справился. в вызове компонента есть пункт отвечающий за мультивыделение ссылок — отключил его и всё норм.

  26. Света

    Алексей, здравствуйте!

    Очень понравилась Ваша статья с комментариями к коду, спасибо за такое детальное описание.

    Подскажите, пожалуйста, решение задачи: у меня 2-хуровневное меню. В 1-м уровне последний пункт должен иметь свой стиль. Я прописала код:
    $aItem ): ?>

    <a href="»> //стиль для последнего пункта

    <a href="»> //стиль для пунктов, кроме последнего


    но условие не работает. Подскажите, пожалуйста, как применить стиль?

  27. Света

    К предыдущему сообщению:

    Я прописала код:
    foreach( $arResult as $key => $aItem )

    if ($arItem[DEPTH_LEVEL] == 1)
    if( $key == (count($arResult)- 1))
    TEXT //стиль для последнего пункта
    else
    TEXT> //стиль для пунктов, кроме последнего
    endif

    но условие не работает. Подскажите, пожалуйста, как применить стиль?

  28. Тхалгат

    огромное спасибо! все разжовано как надо!

  29. Вадим

    Здравствуйте, подскажите как уже созданную страницу добавить в выпадающий список? есть куча созданных страниц, надо их прикрепить к меню (меню изначально было написано в html и указывало на страницы ) теперь надо все страницы прикрепить к горизонтальному меню, сколько пробую никак не получается, при выборе пункта добавить в меню — предлагает верхнее, левое или нижнее. Мне надо добавить некоторые страницы в верхний уровень, а большинство в выпадающий. Как это сделать?

  30. Наталья

    Большое спасибо за комментарии к коду! Очень помогло!

  31. Виталий

    Отлично разжевано, теперь все четко и ясно. Спасибо:)

  32. Ярослав

    Спасибо Алексей Валеев за статью. Комментарии к коду позволили в сжатые сроки сделать свое меню.

  33. Олег

    В приведенном коде имеется ошибка: для пунктов меню, у которых установлен IS_PARENT, права доступа не проверяются.

  34. Андрей

    В самом деле Не чего не понятно!

  35. Ринтат

    Доброво времени суток.
    Я новичок.
    Подскажите где ошибка.

    <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

  36. Анд

    а как можно сделать .current для самой первой, главной кнопки top меню битрикс шаблона ?

  37. Андрей

    А про шаблоны компонентов как catalog.section.list и catalog.list такое будет? Очень бы хотелось

  38. Леонид

    Здравствуйте Алексей!
    Я делаю меню из catalog.section.list, как можно сделать чтоб подсвечивался активный раздел по аналогии $arItem[«SELECTED»], и как сделать проверку на родителя по аналогии $arIrem[«IS_PARENT»]. Подскажите пожалуйста если вас не затруднит!

Добавить комментарий

Ваш адрес email не будет опубликован.