Новичкам – разбираемся с шаблоном меню horizontal_multilevel

Опубликовано 19 Июл 2011

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

Похожие записи

Если вам понравилась статья, подписывайтесь на обновления блога по rss или присоединяйтесь в twitter

Поделиться ссылкой с друзьями:

Метки: , ,

Категории: Bitrix, Css

Комментарии (17)

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

  2. $arResult передается из компонента как результат его работы

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

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

  5. Игорь:

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

  6. Игорь, вложенность можно задать в настройках компонента

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

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

  9. Almat:

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

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

  11. Almat:

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

  12. Это не меню, а сильно измененный catalog.section.list

  13. Almat:

    я могу сделать типа такого http://dobrovoi.ru/files/accordeon1/index.html с помощью vertical-multilevel?? Я делаю интернет магазин чуть-чуть не хватает функционал и дизайн.

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

  15. Михаил, можно, только чуть сложнее с выводом.

  16. phisey:

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

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

Оставить комментарий