Техническая реализация
1. Компонент каталога
result_modifier.php
<?
use Helper\CatalogSectionHelper;
if (!defined("B_PROLOG_INCLUDED") || B_PROLOG_INCLUDED !== true) die();
// Получение иерархической структуры разделов
$arResult = CatalogSectionHelper::getTree(
IBLOCK_CATALOG_ID, // ID инфоблока каталога
false // Флаг отключения загрузки элементов
);
// Формирование левой панели меню
if (!empty($arResult)) {
foreach ($arResult as $section) {
if ($section['DEPTH_LEVEL'] == 1) {
$arResult['LEFT'][] = [
'NAME' => $section['NAME'],
'CODE' => $section['CODE'],
];
}
}
}
2. Шаблон отображения (template.php)
<? if (!empty($arResult)): ?>
<!-- Триггер модального окна -->
<button type="button"
data-bs-toggle="modal"
data-bs-target="#catalogMenuModal"
class="btn btn-primary btn-secondary">
Открыть каталог
</button>
<!-- Контейнер меню -->
<div class="catalog-menu">
<div class="container">
<div class="menu-list">
<!-- Левая панель (родительские разделы) -->
<ul class="main-category-list">
<? foreach ($arResult['LEFT'] as $k => $sectionLeft): ?>
<li class="category-item<?= $k === 0 ? ' active' : ''?>"
onclick="openCategory(event, '<?= $sectionLeft['CODE']?>')">
<span class="category-link">
<?= $sectionLeft['NAME'] ?>
</span>
</li>
<? endforeach ?>
</ul>
<!-- Правая панель (дочерние разделы) -->
<div class="subcategory-list">
<? foreach ($arResult as $i => $section): ?>
<div class="tab-list<?= $i === 0 ? ' active' : ''?>"
id="<?= $section['CODE']?>">
<a class="category-title"
href="<?= $section['DETAIL_PAGE_URL']?>">
<?= $section['NAME'] ?>
</a>
<? if(!empty($section['SUB_SECTIONS'])):
renderSubSection($section['SUB_SECTIONS']);
endif ?>
</div>
<? endforeach ?>
</div>
</div>
</div>
</div>
<? endif ?>
<?
// Рекурсивная функция отрисовки подразделов
function renderSubSection(array $subSections, int $level = 1): void {
foreach ($subSections as $subSection):
?>
<div class="lev-<?= $level ?>">
<a class="sub-title-link"
href="<?= $subSection['DETAIL_PAGE_URL']?>">
<?= $subSection['NAME'] ?>
</a>
<? if (!empty($subSection['SUB_SECTIONS'])):
renderSubSection($subSection['SUB_SECTIONS'], $level + 1);
endif ?>
</div>
<? endforeach } ?>
Вспомогательные классы
CatalogSectionHelper
<?php
namespace Helper;
use Bitrix\Main\{Loader, ORM\Query\Result};
use Bitrix\Iblock\SectionTable;
class CatalogSectionHelper
{
const DEFAULT_SELECT = [
'ID',
'CODE',
'NAME',
'IBLOCK_ID',
'IBLOCK_SECTION_ID',
'DEPTH_LEVEL',
'PICTURE',
'SECTION_PAGE_URL_RAW' => 'IBLOCK.SECTION_PAGE_URL'
];
/**
* Получение древовидной структуры разделов
* @param int|null $iblockId - ID инфоблока
* @param bool $needElements - Флаг загрузки элементов
* @param int $parentSectionId - ID родительского раздела
* @return array
*/
public static function getTree(
?int $iblockId,
bool $needElements,
int $parentSectionId = 0
): array {
if (!Loader::includeModule('iblock')) {
throw new \Exception('Модуль инфоблоков не установлен');
}
$result = [];
$sections = self::getSections($iblockId, $parentSectionId);
foreach ($sections as $section) {
$section['DETAIL_PAGE_URL'] = UrlHelper::getSectionUrl($section);
$section['SUB_SECTIONS'] = self::getTree(
$iblockId,
$needElements,
$section['ID']
);
$result[$section['ID']] = $section;
}
return $result;
}
private static function getSections(
?int $iblockId,
int $parentId
): Result {
return SectionTable::getList([
'select' => self::DEFAULT_SELECT,
'filter' => [
'IBLOCK_ID' => $iblockId,
'IBLOCK_SECTION_ID' => $parentId,
'ACTIVE' => 'Y'
],
'order' => ['LEFT_MARGIN' => 'ASC'],
'cache' => ['ttl' => 3600]
]);
}
}
UrlHelper
<?php
namespace Helper;
class UrlHelper
{
/**
* Генерация ЧПУ для элементов
*/
public static function getDetailPageUrl(array $element): string
{
return \CIBlock::ReplaceDetailUrl(
$element['DETAIL_PAGE_URL'],
$element,
false,
'E'
);
}
/**
* Генерация ЧПУ для разделов
*/
public static function getSectionUrl(array $section): string
{
return \CIBlock::ReplaceDetailUrl(
$section['SECTION_PAGE_URL_RAW'],
$section,
true,
'S'
);
}
}
Интеграция с Bootstrap 5
Основные функции:
-
Модальное окно: Использует стандартный Bootstrap Modal
<div class="modal fade" id="catalogMenuModal"> <div class="modal-dialog modal-fullscreen"> <div class="modal-content"> <!-- Вставка содержимого компонента --> </div> </div> </div> -
Навигация между табами:\ Функция
openCategoryактивирует соответствующие разделы:function openCategory(event, sectionCode) { document.querySelectorAll('.tab-list').forEach(tab => { tab.classList.remove('active'); }); document.getElementById(sectionCode).classList.add('active'); }
Особенности реализации
-
Производительность:
- Кеширование запросов к БД (TTL 3600 сек)
- Рекурсивная загрузка разделов только при необходимости
-
Адаптивность:
- Поддержка мобильных устройств через
modal-fullscreen - Прогрессивное улучшение для JS-отключенных сценариев
- Поддержка мобильных устройств через
-
Расширяемость:
- Возможность подключения элементов инфоблока через параметр
$needElements - Гибкая система классов для кастомизации стилей
- Возможность подключения элементов инфоблока через параметр
Для полной интеграции подключите Bootstrap 5 и добавьте недостающие стили в соответствии с дизайн-системой проекта.