ASP.NET Core 8.0 Razor Pages动态导航菜单:页面切换时保持常驻
解决ASP.NET Core 8 Razor Pages全局动态角色导航菜单问题
核心方案:用ViewComponent封装菜单逻辑
ViewComponent是Razor Pages中处理带后端逻辑的可复用UI组件的最优方案,完美解决布局页无法直接处理后端逻辑的问题,同时能让菜单在所有页面统一显示。
步骤1:创建MenuViewComponent
在项目中新建Components/MenuViewComponent.cs(推荐放在Components目录):
using Microsoft.AspNetCore.Mvc; using System.Data; using System.Collections; public class MenuViewComponent : ViewComponent { private readonly IConfiguration _configuration; // 注入配置,用于调用存储过程 public MenuViewComponent(IConfiguration configuration) { _configuration = configuration; } public async Task<IViewComponentResult> InvokeAsync() { // 获取当前用户的RoleId(根据你的身份验证方式调整,示例从Claims读取) long roleId = long.Parse(User.FindFirst("RoleId")?.Value ?? "1"); var menus = GetMenusForRole(roleId); return View(menus); } // 复用你原有的菜单获取逻辑 private List<Menu> GetMenusForRole(long roleId) { var menuList = new List<Menu>(); ArrayList parameters = new ArrayList { roleId }; DataTable dtMenus = ExecuteStoredProcedure.ExecProc_getDataTable(_configuration, "Stored_Procedure_Name", parameters); foreach (DataRow row in dtMenus.Rows) { menuList.Add(new Menu { formID = Convert.ToInt64(row["Form_ID"].ToString()), formName = row["Form_Title"].ToString(), parentId = row["Form_Parent_ID"] == DBNull.Value ? (long?)null : Convert.ToInt64(row["Form_Parent_ID"].ToString()), formUrl = row["Form_Url"].ToString() }); } return menuList; } } // 确保Menu类在项目中可访问 public class Menu { public long formID { get; set; } public string formName { get; set; } public long? parentId { get; set; } public string formUrl { get; set; } }
步骤2:创建ViewComponent的视图
在Views/Shared/Components/Menu/Default.cshtml创建视图文件,复制你原有的Main.cshtml中的菜单HTML代码:
<ul class="horizontal-list "> @foreach (var menuItem in Model.Where(m => m.parentId == null)) { <li> <a class="dropdown-toggle" href="#" role="button" data-bs-toggle="dropdown" aria-expanded="false">@menuItem.formName</a> <ul class="dropdown-menu"> @foreach (var subMenuItem in Model.Where(m => m.parentId == menuItem.formID)) { @if (Model.Any(m => m.parentId == subMenuItem.formID)) { <li class="dropdown-submenu"> <a class="dropdown-item dropdown-toggle menutext" href="#">@subMenuItem.formName</a> <ul class="dropdown-menu"> @foreach (var subsubMenuItem in Model.Where(m => m.parentId == subMenuItem.formID)) { <li class="dropdown-menu-1"> <a class="dropdown-item menutext" href="@subsubMenuItem.formUrl">@subsubMenuItem.formName</a> </li> } </ul> </li> } else { <li class="dropdown-submenu"> <a class="dropdown-item menutext" href="@subMenuItem.formUrl">@subMenuItem.formName</a> </li> } } </ul> </li> } </ul>
步骤3:在全局布局_Layout.cshtml中引用ViewComponent
打开Views/Shared/_Layout.cshtml,在你希望显示菜单的位置(比如<header>标签内)添加代码:
@await Component.InvokeAsync("Menu")
所有使用该布局的页面都会自动加载动态菜单,页面跳转时菜单随布局一起渲染,保持一致性。
进阶:实现菜单无刷新页面切换(可选)
如果要实现页面切换时菜单不刷新的单页体验,可通过AJAX加载页面内容:
- 在布局页添加内容容器:
<div id="page-content" class="container mt-4"></div>
- 修改菜单链接的点击事件,阻止默认跳转并加载内容:
<script> document.querySelectorAll('.menutext').forEach(link => { link.addEventListener('click', function(e) { e.preventDefault(); const url = this.getAttribute('href'); fetch(url) .then(response => response.text()) .then(html => { document.getElementById('page-content').innerHTML = html; document.title = this.textContent; }); }); }); </script>
注意:目标页面需设置Layout = null;,避免重复加载布局。
内容的提问来源于stack exchange,提问作者Yuvraj Jadhav
相关产品推荐
相关产品推荐

