Blazor Server课程页面NavMenu加载章节与课时的实现方案
解决方案
1. 监听路由变化动态加载章节数据
Blazor Server的NavMenu是持久化组件,页面切换时不会自动重新初始化,核心思路是通过NavigationManager监听路由跳转事件,实时解析当前路由中的课程ID并加载对应章节数据。
实现步骤
- 在
NavMenu.razor中注入NavigationManager和课程数据服务(如ICourseService) - 组件初始化时订阅
LocationChanged事件,同时初始化检查当前路由是否为课程页面 - 路由变化时解析课程ID,调用API获取章节与课时数据,更新UI
- 组件销毁时取消事件订阅,避免内存泄漏
示例代码:
@inject NavigationManager NavManager @inject ICourseService CourseService @implements IDisposable <div class="top-row ps-3 navbar navbar-dark"> <!-- 原有NavMenu固定导航内容 --> </div> <div class="nav-scrollable" id="main-nav"> <nav class="flex-column"> <NavLink class="nav-link" href="" Match="NavLinkMatch.All"> <span class="oi oi-home" aria-hidden="true"></span> 首页 </NavLink> <!-- 动态渲染课程章节导航 --> @if (CurrentCourseChapters != null) { <CourseNavBar Chapters="CurrentCourseChapters" /> } </nav> </div> @code { private List<Chapter> CurrentCourseChapters { get; set; } private IDisposable _locationChangedSubscription; protected override void OnInitialized() { _locationChangedSubscription = NavManager.LocationChanged += OnLocationChanged; LoadCourseChaptersFromRoute(); } private async void OnLocationChanged(object sender, LocationChangedEventArgs e) { await LoadCourseChaptersFromRoute(); } private async Task LoadCourseChaptersFromRoute() { // 解析路由中的课程ID,假设路由格式为 /courses/{courseId} var uriSegments = new Uri(NavManager.Uri).Segments; if (uriSegments.Length >= 2 && uriSegments[1].Equals("courses/", StringComparison.OrdinalIgnoreCase)) { if (int.TryParse(uriSegments[2].TrimEnd('/'), out var courseId)) { CurrentCourseChapters = await CourseService.GetChaptersWithLessonsAsync(courseId); StateHasChanged(); // 通知组件更新UI } } else { // 离开课程页面时清空章节数据 CurrentCourseChapters = null; StateHasChanged(); } } public void Dispose() { _locationChangedSubscription?.Dispose(); } }
2. 全局状态容器共享数据
通过全局状态容器在课程页面与NavMenu间共享章节数据,适合复杂场景下的组件状态同步。
实现步骤
- 创建状态容器类
public class CourseState { public List<Chapter> CurrentChapters { get; private set; } public event Action OnStateChanged; public void SetChapters(List<Chapter> chapters) { CurrentChapters = chapters; OnStateChanged?.Invoke(); } public void ClearChapters() { CurrentChapters = null; OnStateChanged?.Invoke(); } }
- 注册单例服务
在Program.cs中添加:
builder.Services.AddSingleton<CourseState>();
- 课程页面更新状态
@inject ICourseService CourseService @inject CourseState CourseState @page "/courses/{CourseId:int}" <h1>@Course.Title</h1> @code { [Parameter] public int CourseId { get; set; } private Course Course { get; set; } protected override async Task OnParametersSetAsync() { Course = await CourseService.GetCourseAsync(CourseId); var chapters = await CourseService.GetChaptersWithLessonsAsync(CourseId); CourseState.SetChapters(chapters); } public void Dispose() { // 离开页面时清空章节数据 CourseState.ClearChapters(); } }
- NavMenu监听状态变化
@inject CourseState CourseState @implements IDisposable <!-- 原有NavMenu内容 --> @if (CourseState.CurrentChapters != null) { <CourseNavBar Chapters="CourseState.CurrentChapters" /> } @code { protected override void OnInitialized() { CourseState.OnStateChanged += StateHasChanged; } public void Dispose() { CourseState.OnStateChanged -= StateHasChanged; } }
3. 关键注意事项
CourseNavBar组件需接收Chapters参数,使用NavLink生成规范路由(如/courses/{CourseId}/chapters/{ChapterId}/lessons/{LessonId})- 处理路由解析的边界情况(如无效课程ID、非课程页面路由)
- 异步操作需正确使用
async/await,避免阻塞UI - 调用
StateHasChanged()确保数据更新后组件重新渲染
内容的提问来源于stack exchange,提问作者Sohaieb Taha
相关产品推荐
相关产品推荐

