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端点