项目

ASP.NET Core MVC / Razor Pages UI: 导航菜单

每个应用程序都有一个主菜单,允许用户导航到应用程序的页面/屏幕。有些应用程序可能在不同的 UI 部分包含多个菜单。

ABP 是一个模块化应用程序开发框架。每个模块都可能需要向菜单添加项目

因此,ABP提供了一个菜单基础设施,其中:

  • 应用程序或模块可以向菜单添加项目,而无需知道菜单是如何呈现的。
  • 主题正确呈现菜单。

添加菜单项

为了添加菜单项(或操作现有项目),您需要创建一个实现 IMenuContributor 接口的类。

应用程序启动模板 已经包含了一个 IMenuContributor 的实现。因此,您可以在该类中添加项目,而不是创建一个新的。

示例:添加一个包含 CustomersOrders 子菜单项的 CRM 菜单项

using System.Threading.Tasks;
using MyProject.Localization;
using Volo.Abp.UI.Navigation;

namespace MyProject.Web.Menus
{
    public class MyProjectMenuContributor : IMenuContributor
    {
        public async Task ConfigureMenuAsync(MenuConfigurationContext context)
        {
            if (context.Menu.Name == StandardMenus.Main)
            {
                await ConfigureMainMenuAsync(context);
            }
        }

        private async Task ConfigureMainMenuAsync(MenuConfigurationContext context)
        {
            var l = context.GetLocalizer<MyProjectResource>();

            context.Menu.AddItem(
                new ApplicationMenuItem("MyProject.Crm", l["Menu:CRM"])
                    .AddItem(new ApplicationMenuItem(
                        name: "MyProject.Crm.Customers", 
                        displayName: l["Menu:Customers"], 
                        url: "/crm/customers")
                    ).AddItem(new ApplicationMenuItem(
                        name: "MyProject.Crm.Orders", 
                        displayName: l["Menu:Orders"],
                        url: "/crm/orders")
                     )
            );
        }
    }
}
  • 此示例仅向主菜单(StandardMenus.Main:请参阅下面的 标准菜单 部分)添加项目。
  • 它从 context 获取 IStringLocalizer本地化菜单项的显示名称。
  • 将 Customers 和 Orders 作为 CRM 菜单的子项添加。

创建菜单贡献者后,您需要将其添加到模块的 ConfigureServices 方法中的 AbpNavigationOptions

Configure<AbpNavigationOptions>(options =>
{
    options.MenuContributors.Add(new MyProjectMenuContributor());
});

此示例使用了一些本地化键作为显示名称,这些键应在本地化文件中定义:

"Menu:CRM": "CRM",
"Menu:Orders": "订单",
"Menu:Customers": "客户"

有关本地化的更多信息,请参阅本地化文档

运行应用程序时,您将看到添加到主菜单的项目:

nav-main-menu

菜单由当前 UI 主题呈现。因此,根据您的主题,主菜单的外观可能完全不同。

这里有一些关于菜单贡献者的说明:

  • ABP在需要呈现菜单时调用 ConfigureMenuAsync 方法。
  • 每个菜单项都可以有子项。因此,您可以添加具有无限深度的菜单项(但是,您的 UI 主题可能不支持无限深度)。
  • 通常只有叶菜单项有 url。当您单击父菜单时,其子菜单会打开或关闭,您不会导航到父菜单项的 url
  • 如果一个菜单项没有子项且未定义 url,则它不会在 UI 上呈现。这简化了菜单项的授权:您只需授权子项(请参阅下一节)。如果没有子项被授权,则父项会自动消失。

菜单项属性

菜单项有更多选项(ApplicationMenuItem 类的构造函数)。以下是所有可用选项的列表:

  • namestring,必需):菜单项的唯一名称
  • displayNamestring,必需):菜单项的显示名称/文本。您可以像之前所示那样本地化它。
  • urlstring):菜单项的 URL。
  • iconstring):图标名称。开箱即用支持免费的 Font Awesome 图标类。例如:fa fa-book。只要您将必要的 CSS 文件包含到应用程序中,就可以使用任何 CSS 字体图标类。
  • orderint):菜单项的顺序。默认值为 1000。除非指定顺序值,否则项目按添加顺序排序。
  • customDataDictionary<string, object>):一个字典,允许存储自定义对象,您可以将其与菜单项关联并在呈现菜单项时使用它。
  • targetstring):菜单项的目标。对于 Web 应用程序,可以是 null(默认)、"_blank"、"_self"、"_parent"、"_top" 或框架名称。
  • elementIdstring):可用于使用特定的 HTML id 属性呈现元素。
  • cssClassstring):菜单项的附加字符串类。
  • groupNamestring):可用于对菜单项进行分组。

授权

如上所述,菜单贡献者动态地向菜单贡献项目。因此,您可以执行任何自定义逻辑或从任何源获取菜单项。

一个用例是授权。您通常希望通过检查权限来添加菜单项。

示例:检查当前用户是否具有权限

if (await context.IsGrantedAsync("MyPermissionName"))
{
    //...添加菜单项
}

对于授权,您可以使用 RequirePermissions 扩展方法作为快捷方式。它的性能也更高,ABP 为所有项目优化了权限检查。

context.Menu.AddItem(
    new ApplicationMenuItem("MyProject.Crm", l["Menu:CRM"])
        .AddItem(new ApplicationMenuItem(
                name: "MyProject.Crm.Customers",
                displayName: l["Menu:Customers"],
                url: "/crm/customers")
            .RequirePermissions("MyProject.Crm.Customers")
        ).AddItem(new ApplicationMenuItem(
                name: "MyProject.Crm.Orders",
                displayName: l["Menu:Orders"],
                url: "/crm/orders")
            .RequirePermissions("MyProject.Crm.Orders")
        )
);

您可以使用 context.AuthorizationService 直接访问 IAuthorizationService

解析依赖项

context.ServiceProvider 可用于解析任何服务依赖项。

示例:获取服务

var myService = context.ServiceProvider.GetRequiredService<IMyService>();
//...使用服务

您无需关心释放/处理服务。ABP 会处理它。

管理菜单

菜单中有一个由 ABP 添加的特殊菜单项:管理 菜单。它通常由预构建的管理 应用程序模块 使用:

nav-main-menu-administration

如果要在 管理 菜单项下添加菜单项,可以使用 context.Menu.GetAdministration() 扩展方法:

context.Menu.GetAdministration().AddItem(...)

操作现有菜单项

ABP 按模块依赖顺序执行菜单贡献者。因此,您可以操作您的应用程序或模块(直接或间接)依赖的菜单项。

示例:为 Identity Module 添加的 Users 菜单项设置图标

var userMenu = context.Menu.FindMenuItem(IdentityMenuNames.Users);
userMenu.Icon = "fa fa-users";

context.Menu 使您能够访问先前菜单贡献者添加的所有菜单项。

菜单组

您可以定义组并将菜单项与组关联。

示例:

using System.Threading.Tasks;
using MyProject.Localization;
using Volo.Abp.UI.Navigation;

namespace MyProject.Web.Menus
{
    public class MyProjectMenuContributor : IMenuContributor
    {
        public async Task ConfigureMenuAsync(MenuConfigurationContext context)
        {
            if (context.Menu.Name == StandardMenus.Main)
            {
                await ConfigureMainMenuAsync(context);
            }
        }

        private async Task ConfigureMainMenuAsync(MenuConfigurationContext context)
        {
            var l = context.GetLocalizer<MyProjectResource>();

            context.Menu.AddGroup(
                new ApplicationMenuGroup(
                    name: "Main",
                    displayName: l["Main"]
                )
            );
            context.Menu.AddItem(
                new ApplicationMenuItem("MyProject.Crm", l["Menu:CRM"], groupName: "Main")
                    .AddItem(new ApplicationMenuItem(
                        name: "MyProject.Crm.Customers", 
                        displayName: l["Menu:Customers"], 
                        url: "/crm/customers")
                    ).AddItem(new ApplicationMenuItem(
                        name: "MyProject.Crm.Orders", 
                        displayName: l["Menu:Orders"],
                        url: "/crm/orders")
                     )
            );      
        }
    }
}

UI 主题将决定是否呈现组,如果决定呈现,则呈现方式由主题决定。只有 LeptonX 主题实现了菜单组。

标准菜单

菜单是一个命名的组件。一个应用程序可能包含多个具有不同、唯一名称的菜单。有两个预定义的标准菜单:

  • Main:应用程序的主菜单。包含指向应用程序页面的链接。定义为常量:Volo.Abp.UI.Navigation.StandardMenus.Main
  • User:用户个人资料菜单。定义为常量:Volo.Abp.UI.Navigation.StandardMenus.User

上面已经介绍了 Main 菜单。当用户登录时,User 菜单可用:

user-menu

您可以通过检查 context.Menu.Name 来向 User 菜单添加项目,如下所示:

if (context.Menu.Name == StandardMenus.User)
{
    //...添加项目
}

IMenuManager

IMenuManager 通常由 UI 主题用于在 UI 上呈现菜单项。因此,您通常不需要直接使用 IMenuManager

示例:获取 Main 菜单项

using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc.RazorPages;
using Volo.Abp.UI.Navigation;

namespace MyProject.Web.Pages
{
    public class IndexModel : PageModel
    {
        private readonly IMenuManager _menuManager;

        public IndexModel(IMenuManager menuManager)
        {
            _menuManager = menuManager;
        }
        
        public async Task OnGetAsync()
        {
            var mainMenu = await _menuManager.GetAsync(StandardMenus.Main);
            
            foreach (var menuItem in mainMenu.Items)
            {
                //...
            }
        }
    }
}
在本文档中