README.md 18 KB

Компонент MultiLevelMenu - Полная документация

Назначение компонента

MultiLevelMenu - универсальный компонент для создания многоуровневых навигационных меню с поддержкой вложенности, различных тем, адаптивным дизайном и расширенной функциональностью. Компонент автоматически обрабатывает иерархическую структуру данных и предоставляет интуитивную навигацию.

git репозитарий

https://gogs.osvoj.ru/s5l.ru/borbad.s5l.ru/src/master/vue/app/shared/ImageSlider/

Импорт и регистрация

# В основном файле приложения (app/temp.coffee)
components:
    'multilevelmenu': require 'app/shared/MultiLevelMenu'

Базовое использование

Минимальная конфигурация

multilevelmenu(:menuItems="menuData")

С кастомными настройками

multilevelmenu(
    :menuItems="navigationData"
    theme="dark"
    orientation="horizontal"
    :showIcons="true"
    :autoClose="true"
)

Полный список props

menuItems (обязательный)

  • Тип: Array
  • Описание: Массив объектов пунктов меню
  • Структура объекта:

    {
    id: String                    # Уникальный идентификатор
    title: String | Array         # Заголовок пункта (поддерживает мультиязычные массивы)
    url: String                   # Ссылка или маршрут
    icon: String                  # Иконка (название или путь)
    children: Array               # Вложенные пункты меню
    type: String                  # Тип пункта ('link', 'button', 'divider')
    disabled: Boolean             # Отключенное состояние
    visible: Boolean              # Видимость пункта
    target: String                # Целевое окно для ссылок
    permissions: Array            # Права доступа
    badge: String | Number        # Бейдж/уведомление
    badgeColor: String            # Цвет бейджа
    }
    

theme (опциональный)

  • Тип: String
  • По умолчанию: 'light'
  • Допустимые значения: 'light', 'dark', 'primary', 'custom'
  • Описание: Цветовая тема меню

orientation (опциональный)

  • Тип: String
  • По умолчанию: 'horizontal'
  • Допустимые значения: 'horizontal', 'vertical'
  • Описание: Ориентация меню

showIcons (опциональный)

  • Тип: Boolean
  • По умолчанию: true
  • Описание: Показывать иконки пунктов меню

autoClose (опциональный)

  • Тип: Boolean
  • По умолчанию: true
  • Описание: Автоматически закрывать выпадающие меню при клике вне области

maxDepth (опциональный)

  • Тип: Number
  • По умолчанию: 3
  • Описание: Максимальная глубина вложенности меню

activeItem (опциональный)

  • Тип: String
  • По умолчанию: null
  • Описание: ID активного пункта меню

mobileBreakpoint (опциональный)

  • Тип: Number
  • По умолчанию: 768
  • Описание: Breakpoint для мобильной версии (в px)

animationType (опциональный)

  • Тип: String
  • По умолчанию: 'fade'
  • Допустимые значения: 'fade', 'slide', 'scale', 'none'
  • Описание: Тип анимации выпадающих меню

События (Events)

@item-click

  • Описание: Событие клика по пункту меню
  • Payload:

    {
    item: Object,           # Объект пункта меню
    event: Event,           # Нативное событие
    level: Number,          # Уровень вложенности
    path: Array            # Путь от корня
    }
    

@item-hover

  • Описание: Событие наведения на пункт меню
  • Payload: Аналогично item-click

@menu-open

  • Описание: Событие открытия подменю
  • Payload:

    {
    item: Object,           # Родительский пункт
    level: Number,          # Уровень
    items: Array           # Дочерние пункты
    }
    

@menu-close

  • Описание: Событие закрытия подменю
  • Payload: Аналогично menu-open

@active-change

  • Описание: Событие изменения активного пункта
  • Payload:

    {
    oldItem: Object,        # Предыдущий активный пункт
    newItem: Object,        # Новый активный пункт
    level: Number          # Уровень изменения
    }
    

Слоты (Slots)

[item-content] (кастомизация содержимого пункта)

  • Props:

    {
    item: Object,           # Объект пункта меню
    level: Number,          # Уровень вложенности
    isActive: Boolean,      # Активное состояние
    hasChildren: Boolean    # Наличие дочерних элементов
    }
    
  • Пример:

    multilevelmenu(:menuItems="menuData")
      template([item-content]="{ item, level, isActive }")
          div(class="flex items-center space-x-3")
              icon(:name="item.icon" class="w-5 h-5")
              span {{ item.title }}
              badge(v-if="item.badge" :count="item.badge")
    

[item-icon] (кастомизация иконки)

  • Props: Аналогично item-content
  • Пример:

    multilevelmenu(:menuItems="menuData")
      template([item-icon]="{ item }")
          custom-icon(:name="item.icon")
    

[item-badge] (кастомизация бейджа)

  • Props: Аналогично item-content
  • Пример:

    multilevelmenu(:menuItems="menuData")
      template([item-badge]="{ item }")
          div(class="bg-red-500 text-white rounded-full px-2 py-1 text-xs")
              {{ item.badge }}
    

[before-menu] (контент перед меню)

  • Пример:

    multilevelmenu(:menuItems="menuData")
      template([before-menu])
          div(class="p-4 border-b")
              p Добро пожаловать!
    

[after-menu] (контент после меню)

  • Пример:

    multilevelmenu(:menuItems="menuData")
      template([after-menu])
          div(class="p-4 border-t")
              app-link(to="/help") Помощь
    

Методы компонента

openSubmenu(itemId)

  • Описание: Программное открытие подменю
  • Параметры: itemId - ID пункта меню
  • Пример:

    @$refs.menu.openSubmenu('events')
    

closeSubmenu(itemId)

  • Описание: Программное закрытие подменю
  • Параметры: itemId - ID пункта меню
  • Пример:

    @$refs.menu.closeSubmenu('events')
    

closeAll()

  • Описание: Закрыть все открытые подменю
  • Пример:

    @$refs.menu.closeAll()
    

setActive(itemId)

  • Описание: Установить активный пункт меню
  • Параметры: itemId - ID пункта меню
  • Пример:

    @$refs.menu.setActive('current-page')
    

updateMenu(newItems)

  • Описание: Обновить данные меню
  • Параметры: newItems - новый массив пунктов меню
  • Пример:

    @$refs.menu.updateMenu(updatedMenuData)
    

getActiveItem()

  • Описание: Получить текущий активный пункт
  • Возвращает: Объект активного пункта меню
  • Пример:

    activeItem = @$refs.menu.getActiveItem()
    

getMenuPath(itemId)

  • Описание: Получить путь к пункту меню
  • Параметры: itemId - ID пункта меню
  • Возвращает: Массив ID от корня до пункта
  • Пример:

    path = @$refs.menu.getMenuPath('deep-item')
    

Примеры использования в различных сценариях

1. Основная навигация сайта

multilevelmenu(
    :menuItems="mainNavigation"
    theme="light"
    orientation="horizontal"
    :showIcons="false"
    @item-click="handleNavClick"
)

2. Боковое меню администратора

multilevelmenu(
    :menuItems="adminMenu"
    theme="dark"
    orientation="vertical"
    :maxDepth="4"
    :activeItem="currentAdminSection"
    @active-change="onAdminSectionChange"
)

3. Мобильное меню с кастомизацией

multilevelmenu(
    :menuItems="mobileMenu"
    theme="primary"
    orientation="vertical"
    :mobileBreakpoint="1024"
    :animationType="slide"
)
    template([item-content]="{ item, level }")
        div(class="flex items-center justify-between py-3")
            div(class="flex items-center space-x-4")
                icon(:name="item.icon" class="w-6 h-6")
                span(class="text-lg") {{ item.title }}
            icon(
                v-if="item.children"
                name="chevron-right"
                class="w-4 h-4 transform transition-transform"
                :class="{ 'rotate-90': isOpen }"
            )

4. Меню с правами доступа

multilevelmenu(
    :menuItems="filteredMenu"
    @item-click="checkPermissions"
)

5. Мега-меню с различными типами контента

multilevelmenu(:menuItems="megaMenuData")
    template([item-content]="{ item, level }")
        div(v-if="level === 1 && item.type === 'mega'")
            div(class="grid grid-cols-3 gap-8 p-6")
                div(v-for="section in item.sections")
                    h4(class="font-semibold mb-3") {{ section.title }}
                    div(class="space-y-2")
                        app-link(
                            v-for="link in section.links"
                            :to="link.url"
                            class="block text-gray-600 hover:text-blue-600"
                        ) {{ link.title }}

Структура данных меню

Базовый пример

menuData = [
    {
        id: 'home'
        title: ['Главная', 'Home', 'Асосӣ']
        url: '/'
        icon: 'home'
        visible: true
    }
    {
        id: 'events'
        title: ['Мероприятия', 'Events', 'Чорабиниҳо']
        url: '/events'
        icon: 'calendar'
        children: [
            {
                id: 'concerts'
                title: ['Концерты', 'Concerts', 'Консертҳо']
                url: '/events/concerts'
                icon: 'music'
            }
            {
                id: 'exhibitions'
                title: ['Выставки', 'Exhibitions', 'Намоишҳо']
                url: '/events/exhibitions'
                icon: 'palette'
            }
        ]
    }
    {
        id: 'blog'
        title: ['Блог', 'Blog', 'Блог']
        url: '/blog'
        icon: 'news'
        badge: 5
        badgeColor: 'red'
    }
    {
        type: 'divider'
    }
    {
        id: 'contacts'
        title: ['Контакты', 'Contacts', 'Тамос']
        url: '/contacts'
        icon: 'phone'
        disabled: false
    }
]

Расширенная структура с пермишенами

advancedMenu = [
    {
        id: 'dashboard'
        title: 'Дашборд'
        url: '/admin'
        icon: 'dashboard'
        permissions: ['admin', 'moderator']
        children: [
            {
                id: 'users'
                title: 'Пользователи'
                url: '/admin/users'
                permissions: ['admin']
            }
            {
                id: 'content'
                title: 'Контент'
                url: '/admin/content'
                permissions: ['admin', 'editor']
            }
        ]
    }
]

Темы и стилизация

Встроенные темы

  • light - светлая тема с белым фоном
  • dark - темная тема с серым фоном
  • primary - тема с основным цветом бренда
  • custom - для полной кастомизации через CSS

Кастомизация через CSS переменные

.multilevel-menu
    --menu-bg: theme('colors.white')
    --menu-text: theme('colors.gray.800')
    --menu-hover-bg: theme('colors.gray.100')
    --menu-active-bg: theme('colors.blue.500')
    --menu-active-text: theme('colors.white')
    --menu-border: theme('colors.gray.200')
    --menu-shadow: 0 10px 15px -3px rgba(0, 0, 0, 0.1)

Кастомизация через классы

multilevelmenu(
    :menuItems="menuData"
    class="custom-menu"
)
.custom-menu
    .menu-item
        @apply px-6 py-3 border-l-4 border-transparent
        
        &.active
            @apply border-blue-500 bg-blue-50
            
        &:hover
            @apply bg-gray-50

Адаптивность и мобильная версия

Автоматическая адаптация

  • Горизонтальное меню на десктопе
  • Вертикальное выдвижное меню на мобильных
  • Настраиваемый breakpoint
  • Touch-оптимизированные взаимодействия

Кастомизация мобильной версии

multilevelmenu(
    :menuItems="menuData"
    :mobileBreakpoint="1024"
    mobileHeader="Навигация"
    :showMobileHeader="true"
)

Интеграция с системой прав доступа

Фильтрация меню по правам

computed:
    filteredMenu: ->
        userPermissions = @$store.state.user.permissions
        return @filterMenuByPermissions(@menuData, userPermissions)

methods:
    filterMenuByPermissions: (menuItems, permissions) ->
        return menuItems.filter (item) =>
            if item.permissions
                return item.permissions.some (perm) -> permissions.includes(perm)
            return true

Best Practices

1. Оптимизация структуры данных

# Правильно - плоская структура с ссылками на детей
menuData = [
    { id: 'parent', title: 'Родитель', url: '/parent' },
    { id: 'child', title: 'Ребенок', url: '/child', parentId: 'parent' }
]

# Неправильно - глубоко вложенные объекты
menuData = [
    { 
        title: 'Родитель', 
        children: [
            { title: 'Ребенок', children: [...] }
        ] 
    }
]

2. Использование мультиязычных массивов

menuItem = 
    title: ['Русский текст', 'English text', 'Тоҷикӣ матн']
    # Компонент автоматически выберет нужный язык

3. Правильная обработка событий

methods:
    handleMenuClick: ({ item, event, level }) ->
        # Предотвращаем переход для специальных пунктов
        if item.type is 'button'
            event.preventDefault()
            @handleButtonAction(item)
        
        # Логируем навигацию
        analytics.track('menu_click', { 
            item: item.id,
            level: level 
        })

4. Оптимизация производительности

<!-- Правильно - стабильные ID -->
multilevelmenu(:menuItems="menuData" :key="menuVersion")

<!-- Неправильно - изменяемые ID -->
multilevelmenu(:menuItems="dynamicMenu")

Отладка и разработка

Включение режима отладки

multilevelmenu(
    :menuItems="menuData"
    debug
    @item-click="console.log"
    @menu-open="console.log"
)

Проверка состояния меню

# В консоли разработчика
$refs.menu.getActiveItem()
$refs.menu.getMenuPath('item-id')

Компонент MultiLevelMenu предоставляет мощный и гибкий инструмент для создания сложных навигационных систем с поддержкой многоуровневой структуры, адаптивным дизайном и расширенными возможностями кастомизации.