You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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加载页面内容:

  1. 在布局页添加内容容器:
<div id="page-content" class="container mt-4"></div>
  1. 修改菜单链接的点击事件,阻止默认跳转并加载内容:
<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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.21 03:11:01