导航架构Skill navigation-architecture

导航架构技能专注于设计网站和应用中的导航系统,包括菜单层次、面包屑轨迹、巨型菜单结构、移动导航模式以及导航API。适用于无头CMS架构,帮助开发者构建用户友好的导航体验。关键词:菜单设计、面包屑生成、导航API、响应式导航、无头CMS。

架构设计 0 次安装 0 次浏览 更新于 3/11/2026

name: 导航架构 description: 用于设计菜单系统、面包屑、巨型菜单或导航API。涵盖菜单层次结构、动态与静态导航、移动导航模式以及无头CMS的导航端点设计。 allowed-tools: 读取, 全局, 搜索, 任务, 技能

导航架构

为无头CMS架构设计菜单系统、面包屑和导航API的指导。

何时使用此技能

  • 设计主要/次要导航
  • 实现面包屑轨迹
  • 构建巨型菜单结构
  • 创建移动导航模式
  • 设计导航API

菜单类型

主要导航

主站导航,通常在头部。

public class Menu
{
    public Guid Id { get; set; }
    public string Name { get; set; } = string.Empty;
    public string Slug { get; set; } = string.Empty;
    public MenuLocation Location { get; set; }
    public List<MenuItem> Items { get; set; } = new();
}

public class MenuItem
{
    public Guid Id { get; set; }
    public string Label { get; set; } = string.Empty;

    // 链接目标(其中之一)
    public Guid? PageId { get; set; }
    public string? ExternalUrl { get; set; }
    public string? Anchor { get; set; }

    // 计算URL
    public string Url { get; set; } = string.Empty;

    // 层次结构
    public Guid? ParentId { get; set; }
    public List<MenuItem> Children { get; set; } = new();
    public int Order { get; set; }

    // 显示选项
    public bool OpenInNewTab { get; set; }
    public string? Icon { get; set; }
    public string? CssClass { get; set; }
}

public enum MenuLocation
{
    Primary,    // 主要
    Secondary,  // 次要
    Footer,     // 页脚
    Sidebar,    // 侧边栏
    Utility,    // 实用工具
    Mobile      // 移动
}

巨型菜单

具有多列和特色内容的复杂导航。

public class MegaMenuItem : MenuItem
{
    // 巨型菜单特定
    public bool IsMegaMenu { get; set; }
    public int Columns { get; set; } = 4;

    // 特色内容
    public Guid? FeaturedContentId { get; set; }
    public string? FeaturedImageUrl { get; set; }
    public string? Description { get; set; }

    // 列组
    public List<MenuColumn> MenuColumns { get; set; } = new();
}

public class MenuColumn
{
    public string? Heading { get; set; }
    public List<MenuItem> Items { get; set; } = new();
}

页脚导航

public class FooterMenu
{
    public List<FooterSection> Sections { get; set; } = new();
    public List<MenuItem> LegalLinks { get; set; } = new();
    public List<SocialLink> SocialLinks { get; set; } = new();
}

public class FooterSection
{
    public string Heading { get; set; } = string.Empty;
    public List<MenuItem> Links { get; set; } = new();
}

public class SocialLink
{
    public string Platform { get; set; } = string.Empty;
    public string Url { get; set; } = string.Empty;
    public string? Icon { get; set; }
}

面包屑

面包屑生成

public class BreadcrumbService
{
    public async Task<List<Breadcrumb>> GetBreadcrumbsAsync(Page page)
    {
        var breadcrumbs = new List<Breadcrumb>
        {
            new Breadcrumb { Label = "主页", Url = "/" }
        };

        // 向上遍历页面层次结构
        var ancestors = await GetAncestorsAsync(page);
        foreach (var ancestor in ancestors)
        {
            breadcrumbs.Add(new Breadcrumb
            {
                Label = ancestor.Title,
                Url = ancestor.Path
            });
        }

        // 当前页面(无链接)
        breadcrumbs.Add(new Breadcrumb
        {
            Label = page.Title,
            Url = null,
            IsCurrent = true
        });

        return breadcrumbs;
    }
}

public class Breadcrumb
{
    public string Label { get; set; } = string.Empty;
    public string? Url { get; set; }
    public bool IsCurrent { get; set; }
}

用于SEO的结构化数据

public class BreadcrumbSchemaGenerator
{
    public string GenerateJsonLd(List<Breadcrumb> breadcrumbs, string baseUrl)
    {
        var items = breadcrumbs.Select((b, i) => new
        {
            @type = "ListItem",
            position = i + 1,
            name = b.Label,
            item = b.Url != null ? $"{baseUrl}{b.Url}" : null
        }).ToList();

        var schema = new
        {
            @context = "https://schema.org",
            @type = "BreadcrumbList",
            itemListElement = items
        };

        return JsonSerializer.Serialize(schema);
    }
}

动态与静态菜单

动态菜单(基于页面)

public class DynamicMenuService
{
    public async Task<Menu> GenerateFromPagesAsync(
        int maxDepth = 2,
        bool publishedOnly = true)
    {
        var pages = await _pageRepository.GetPublishedPagesAsync();

        var rootPages = pages
            .Where(p => p.ParentId == null && p.ShowInNavigation)
            .OrderBy(p => p.Order);

        var menu = new Menu
        {
            Name = "主导航",
            Slug = "main",
            Location = MenuLocation.Primary
        };

        foreach (var page in rootPages)
        {
            var item = await BuildMenuItemAsync(page, pages, 1, maxDepth);
            menu.Items.Add(item);
        }

        return menu;
    }

    private async Task<MenuItem> BuildMenuItemAsync(
        Page page,
        IEnumerable<Page> allPages,
        int currentDepth,
        int maxDepth)
    {
        var item = new MenuItem
        {
            Id = page.Id,
            Label = page.NavigationTitle ?? page.Title,
            PageId = page.Id,
            Url = page.Path,
            Order = page.Order
        };

        if (currentDepth < maxDepth)
        {
            var children = allPages
                .Where(p => p.ParentId == page.Id && p.ShowInNavigation)
                .OrderBy(p => p.Order);

            foreach (var child in children)
            {
                var childItem = await BuildMenuItemAsync(
                    child, allPages, currentDepth + 1, maxDepth);
                item.Children.Add(childItem);
            }
        }

        return item;
    }
}

静态菜单(CMS管理)

public class StaticMenuService
{
    public async Task<Menu> GetMenuAsync(string slug)
    {
        var menu = await _menuRepository.GetBySlugAsync(slug);
        if (menu == null) return null!;

        // 解析页面链接项的URL
        foreach (var item in menu.Items.SelectMany(FlattenItems))
        {
            if (item.PageId.HasValue)
            {
                var page = await _pageRepository.GetAsync(item.PageId.Value);
                item.Url = page?.Path ?? "#";
            }
        }

        return menu;
    }

    private IEnumerable<MenuItem> FlattenItems(MenuItem item)
    {
        yield return item;
        foreach (var child in item.Children.SelectMany(FlattenItems))
        {
            yield return child;
        }
    }
}

导航API

REST端点

GET /api/menus                    # 列出所有菜单
GET /api/menus/{slug}             # 通过slug获取菜单
GET /api/menus/location/{location} # 通过位置获取菜单
GET /api/breadcrumbs?path=/about  # 获取路径的面包屑

菜单响应

{
  "data": {
    "id": "menu-123",
    "name": "主导航",
    "slug": "main",
    "location": "Primary",
    "items": [
      {
        "id": "item-1",
        "label": "产品",
        "url": "/products",
        "children": [
          {
            "id": "item-2",
            "label": "软件",
            "url": "/products/software",
            "children": []
          },
          {
            "id": "item-3",
            "label": "硬件",
            "url": "/products/hardware",
            "children": []
          }
        ]
      },
      {
        "id": "item-4",
        "label": "关于",
        "url": "/about",
        "children": []
      },
      {
        "id": "item-5",
        "label": "联系",
        "url": "/contact",
        "children": []
      }
    ]
  }
}

面包屑响应

{
  "data": [
    { "label": "主页", "url": "/" },
    { "label": "产品", "url": "/products" },
    { "label": "软件", "url": "/products/software" },
    { "label": "企业套件", "url": null, "isCurrent": true }
  ],
  "jsonLd": "<script type=\"application/ld+json\">...</script>"
}

移动导航模式

汉堡菜单

public class MobileMenuConfig
{
    public bool UseHamburger { get; set; } = true;
    public HamburgerStyle Style { get; set; } = HamburgerStyle.SlideIn;
    public int MaxVisibleItems { get; set; } = 5;
    public bool ShowSearch { get; set; } = true;
}

public enum HamburgerStyle
{
    SlideIn,    // 从侧面滑入
    Overlay,    // 全屏覆盖
    Dropdown    // 从头部下拉
}

响应式导航策略

断点 导航风格
桌面 (>1024px) 完整水平菜单带下拉
平板 (768-1024px) 压缩菜单,巨型菜单折叠
移动 (<768px) 汉堡菜单,手风琴子菜单

最佳实践

菜单设计

做:
- 限制主要导航为5-7项
- 使用清晰、面向操作的标签
- 保持层次浅(最多2-3级)
- 高亮当前页面/部分
- 使菜单可键盘访问

不做:
- 创建深度嵌套菜单
- 使用模糊标签如“更多”或“杂项”
- 将重要页面隐藏在子菜单中
- 忘记移动用户

性能

// 缓存菜单 - 它们变化不频繁
public class CachedMenuService
{
    private readonly IMemoryCache _cache;
    private readonly TimeSpan _cacheDuration = TimeSpan.FromMinutes(30);

    public async Task<Menu> GetMenuAsync(string slug)
    {
        var cacheKey = $"menu:{slug}";

        if (!_cache.TryGetValue(cacheKey, out Menu? menu))
        {
            menu = await _menuRepository.GetBySlugAsync(slug);
            _cache.Set(cacheKey, menu, _cacheDuration);
        }

        return menu!;
    }
}

相关技能

  • page-structure-design - 导航的页面层次结构
  • url-routing-patterns - 菜单链接的URL结构
  • headless-api-design - 导航API端点