서브메뉴 구현

서브메뉴 구현

서브메뉴는 현재 선택된 메뉴의 하위 메뉴만 표시하는 내비게이션입니다. 주로 사이드바나 페이지 상단에 위치합니다.

기본 서브메뉴

선택된 1차 메뉴의 2차 메뉴 표시

<!-- 현재 선택된 1차 메뉴 찾기 -->
<nav class="submenu" cond="$main_menu">
    <block loop="$main_menu->list => $key1, $val1" cond="$val1['selected'] && $val1['list']">
        <h3 class="submenu-title">{$val1['link']}</h3>
        <ul class="submenu-list">
            <li loop="$val1['list'] => $key2, $val2" 
                class="active"|cond="$val2['selected']">
                <a href="{$val2['href']}">{$val2['link']}</a>
            </li>
        </ul>
    </block>
</nav>

3단계까지 표시하는 서브메뉴

<aside class="sidebar-menu">
    <block loop="$main_menu->list => $key1, $val1" cond="$val1['selected']">
        <!-- 1차 메뉴 제목 -->
        <h2 class="menu-title">
            <a href="{$val1['href']}">{$val1['link']}</a>
        </h2>

        <!-- 2차 메뉴 -->
        <ul class="depth2" cond="$val1['list']">
            <li loop="$val1['list'] => $key2, $val2" 
                class="{$val2['selected'] ? 'active' : ''} {$val2['list'] ? 'has-child' : ''}">

                <a href="{$val2['href']}">{$val2['link']}</a>

                <!-- 3차 메뉴 -->
                <ul class="depth3" cond="$val2['list']">
                    <li loop="$val2['list'] => $key3, $val3"
                        class="active"|cond="$val3['selected']">
                        <a href="{$val3['href']}">{$val3['link']}</a>
                    </li>
                </ul>
            </li>
        </ul>
    </block>
</aside>

아코디언 스타일 서브메뉴

HTML 구조

<nav class="accordion-menu">
    <block loop="$main_menu->list => $key1, $val1" cond="$val1['selected'] && $val1['list']">
        <ul class="accordion-list">
            <li loop="$val1['list'] => $key2, $val2" 
                class="accordion-item {$val2['selected'] ? 'active' : ''}">

                <!-- 2차 메뉴 헤더 -->
                <div class="accordion-header">
                    <a href="{$val2['href']}" class="accordion-link">
                        {$val2['link']}
                    </a>
                    <button class="accordion-toggle" cond="$val2['list']">
                        <i class="icon-chevron-down"></i>
                    </button>
                </div>

                <!-- 3차 메뉴 패널 -->
                <div class="accordion-panel" cond="$val2['list']">
                    <ul class="accordion-content">
                        <li loop="$val2['list'] => $key3, $val3"
                            class="active"|cond="$val3['selected']">
                            <a href="{$val3['href']}">{$val3['link']}</a>
                        </li>
                    </ul>
                </div>
            </li>
        </ul>
    </block>
</nav>

JavaScript

jQuery(function($) {
    // 아코디언 초기화
    $('.accordion-menu').each(function() {
        var $menu = $(this);

        // 활성 메뉴 열기
        $menu.find('.accordion-item.active > .accordion-panel').show();
        $menu.find('.accordion-item.active > .accordion-header .icon-chevron-down')
             .addClass('rotated');

        // 토글 버튼 클릭
        $menu.on('click', '.accordion-toggle', function(e) {
            e.preventDefault();

            var $item = $(this).closest('.accordion-item');
            var $panel = $item.find('> .accordion-panel');
            var $icon = $(this).find('i');

            // 현재 아이템 토글
            $panel.slideToggle(300);
            $icon.toggleClass('rotated');

            // 다른 아이템 닫기 (옵션)
            if ($menu.data('close-others')) {
                $item.siblings().find('> .accordion-panel').slideUp(300);
                $item.siblings().find('.icon-chevron-down').removeClass('rotated');
            }
        });
    });
});

CSS 스타일

/* 아코디언 메뉴 */
.accordion-menu {
    border: 1px solid #e0e0e0;
    border-radius: 4px;
    overflow: hidden;
}

.accordion-list {
    list-style: none;
    margin: 0;
    padding: 0;
}

.accordion-item {
    border-bottom: 1px solid #e0e0e0;
}

.accordion-item:last-child {
    border-bottom: none;
}

/* 헤더 */
.accordion-header {
    display: flex;
    align-items: center;
    background: #f8f9fa;
}

.accordion-header:hover {
    background: #e9ecef;
}

.accordion-item.active > .accordion-header {
    background: #007bff;
}

.accordion-item.active > .accordion-header .accordion-link {
    color: white;
}

.accordion-link {
    flex: 1;
    padding: 15px 20px;
    color: #333;
    text-decoration: none;
}

.accordion-toggle {
    width: 50px;
    height: 50px;
    background: none;
    border: none;
    cursor: pointer;
    display: flex;
    align-items: center;
    justify-content: center;
}

.accordion-toggle i {
    transition: transform 0.3s;
}

.accordion-toggle i.rotated {
    transform: rotate(180deg);
}

/* 패널 */
.accordion-panel {
    display: none;
    background: white;
}

.accordion-content {
    list-style: none;
    margin: 0;
    padding: 0;
}

.accordion-content li {
    border-top: 1px solid #f0f0f0;
}

.accordion-content a {
    display: block;
    padding: 12px 20px 12px 40px;
    color: #666;
    text-decoration: none;
}

.accordion-content a:hover {
    background: #f8f9fa;
    color: #333;
}

.accordion-content .active a {
    background: #e3f2fd;
    color: #007bff;
    font-weight: 500;
}

탭 스타일 서브메뉴

<nav class="tab-submenu">
    <block loop="$main_menu->list => $key1, $val1" cond="$val1['selected'] && $val1['list']">
        <!-- 탭 헤더 -->
        <ul class="tab-header">
            <li loop="$val1['list'] => $key2, $val2" 
                class="tab-item {$val2['selected'] ? 'active' : ''}">
                <a href="{$val2['href']}" class="tab-link">
                    {$val2['link']}
                </a>
            </li>
        </ul>

        <!-- 탭 콘텐츠 (3차 메뉴) -->
        <div class="tab-content">
            <block loop="$val1['list'] => $key2, $val2" cond="$val2['selected'] && $val2['list']">
                <ul class="tab-panel active">
                    <li loop="$val2['list'] => $key3, $val3">
                        <a href="{$val3['href']}" 
                           class="active"|cond="$val3['selected']">
                            {$val3['link']}
                        </a>
                    </li>
                </ul>
            </block>
        </div>
    </block>
</nav>

수직 사이드바 메뉴

<aside class="vertical-menu">
    <block loop="$main_menu->list => $key1, $val1" cond="$val1['selected']">
        <!-- 메뉴 헤더 -->
        <div class="menu-header">
            <h3>{$val1['link']}</h3>
            <a href="{$val1['href']}" class="view-all">전체보기 →</a>
        </div>

        <!-- 메뉴 본문 -->
        <div class="menu-body" cond="$val1['list']">
            <ul class="menu-list">
                <li loop="$val1['list'] => $key2, $val2" 
                    class="menu-item {$val2['selected'] ? 'active' : ''}">

                    <a href="{$val2['href']}" class="menu-link">
                        <span class="link-text">{$val2['link']}</span>
                        <span class="link-badge" cond="$val2['new_count']">
                            {$val2['new_count']}
                        </span>
                    </a>

                    <!-- 하위 메뉴 -->
                    <ul class="submenu-list" cond="$val2['list']">
                        <li loop="$val2['list'] => $key3, $val3">
                            <a href="{$val3['href']}" 
                               class="active"|cond="$val3['selected']">
                                - {$val3['link']}
                            </a>
                        </li>
                    </ul>
                </li>
            </ul>
        </div>
    </block>
</aside>

플로팅 서브메뉴

스크롤 시 따라다니는 서브메뉴:

<div class="floating-submenu" id="floatingMenu">
    <nav class="sticky-menu">
        <!-- 서브메뉴 내용 -->
        <block loop="$main_menu->list => $key1, $val1" cond="$val1['selected'] && $val1['list']">
            <ul>
                <li loop="$val1['list'] => $key2, $val2">
                    <a href="{$val2['href']}" 
                       class="active"|cond="$val2['selected']"
                       data-scroll-to="#{$val2['mid']}">
                        {$val2['link']}
                    </a>
                </li>
            </ul>
        </block>
    </nav>
</div>

<script>
jQuery(function($) {
    var $floatingMenu = $('#floatingMenu');
    var menuTop = $floatingMenu.offset().top;
    var $window = $(window);

    // 스크롤 이벤트
    $window.scroll(function() {
        var scrollTop = $window.scrollTop();

        if (scrollTop > menuTop - 20) {
            $floatingMenu.addClass('fixed');
        } else {
            $floatingMenu.removeClass('fixed');
        }
    });

    // 부드러운 스크롤
    $floatingMenu.on('click', 'a[data-scroll-to]', function(e) {
        e.preventDefault();
        var target = $(this).data('scroll-to');
        var $target = $(target);

        if ($target.length) {
            $('html, body').animate({
                scrollTop: $target.offset().top - 80
            }, 500);
        }
    });
});
</script>

모바일 서브메뉴

슬라이드 메뉴

<div class="mobile-submenu">
    <!-- 현재 페이지 표시 -->
    <button class="current-menu-toggle">
        <span class="current-title">
            <block loop="$main_menu->list => $key1, $val1">
                <block loop="$val1['list'] => $key2, $val2" cond="$val2['selected']">
                    {$val2['link']}
                </block>
            </block>
        </span>
        <i class="icon-chevron-down"></i>
    </button>

    <!-- 슬라이드 패널 -->
    <div class="slide-panel">
        <block loop="$main_menu->list => $key1, $val1" cond="$val1['selected'] && $val1['list']">
            <ul class="mobile-menu-list">
                <li loop="$val1['list'] => $key2, $val2">
                    <a href="{$val2['href']}" 
                       class="active"|cond="$val2['selected']">
                        {$val2['link']}
                    </a>
                </li>
            </ul>
        </block>
    </div>
</div>

브레드크럼과 연동

<div class="page-navigation">
    <!-- 브레드크럼 -->
    <nav class="breadcrumb">
        <a href="{getUrl()}">홈</a>
        <block loop="$main_menu->list => $key1, $val1" cond="$val1['selected']">
            <span class="sep">›</span>
            <a href="{$val1['href']}">{$val1['link']}</a>
            <block loop="$val1['list'] => $key2, $val2" cond="$val2['selected']">
                <span class="sep">›</span>
                <a href="{$val2['href']}">{$val2['link']}</a>
                <block loop="$val2['list'] => $key3, $val3" cond="$val3['selected']">
                    <span class="sep">›</span>
                    <span class="current">{$val3['link']}</span>
                </block>
            </block>
        </block>
    </nav>

    <!-- 서브메뉴 -->
    <nav class="submenu-inline">
        <block loop="$main_menu->list => $key1, $val1" cond="$val1['selected'] && $val1['list']">
            <ul>
                <li loop="$val1['list'] => $key2, $val2">
                    <a href="{$val2['href']}" 
                       class="active"|cond="$val2['selected']">
                        {$val2['link']}
                    </a>
                </li>
            </ul>
        </block>
    </nav>
</div>

설정 옵션

info.xml에서 서브메뉴 관련 설정:

<extra_vars>
    <var name="submenu_type" type="select">
        <title xml:lang="ko">서브메뉴 타입</title>
        <options value="basic">
            <title xml:lang="ko">기본</title>
        </options>
        <options value="accordion">
            <title xml:lang="ko">아코디언</title>
        </options>
        <options value="tab">
            <title xml:lang="ko">탭</title>
        </options>
    </var>

    <var name="submenu_position" type="select">
        <title xml:lang="ko">서브메뉴 위치</title>
        <options value="sidebar">
            <title xml:lang="ko">사이드바</title>
        </options>
        <options value="top">
            <title xml:lang="ko">상단</title>
        </options>
    </var>

    <var name="show_depth3" type="select">
        <title xml:lang="ko">3차 메뉴 표시</title>
        <options value="Y">
            <title xml:lang="ko">표시</title>
        </options>
        <options value="N">
            <title xml:lang="ko">숨김</title>
        </options>
    </var>
</extra_vars>