ABP入门系列(6)——定义导航菜单

ABP入门系列目录——学习Abp框架之实操演练
源码路径:Github-LearningMpaAbp


完成了增删改查以及页面展示,这一节我们来为任务清单添加【导航菜单】。
在以往的项目中,大家可能会手动在layout页面中添加一个a标签来新增导航菜单,这也是一种方式,但是如果要针对不同用户不同权限决定是否显示某个菜单,那么直接在layout页面中去控制就不方便了。
不过,ABP已经为大家考虑了这一点,集成了通用的创建和显示菜单的方式。其主要代码集成在Abp.Application.Navigation命名空间下,相应源码在此
下面我们就来梳理下导航菜单是如何实现和使用。

一、如何使用Abp集成的导航菜单

针对我们的『任务清单』Deom,我们需要在导航栏上添加一个【Task List】的菜单入口。

1.打开web展现层,定位到App_Start/xxxNavigationProvider.cs。

    public class LearningMpaAbpNavigationProvider : NavigationProvider
    {
        public override void SetNavigation(INavigationProviderContext context)
        {
            context.Manager.MainMenu
                .AddItem(
                    new MenuItemDefinition(
                        "Home",
                        L("HomePage"),
                        url: "",
                        icon: "fa fa-home",
                        requiresAuthentication: true
                        )
                ).AddItem(
                    new MenuItemDefinition(
                        "Tenants",
                        L("Tenants"),
                        url: "Tenants",
                        icon: "fa fa-globe",
                        requiredPermissionName: PermissionNames.Pages_Tenants
                        )
                ).AddItem(
                    new MenuItemDefinition(
                        "Users",
                        L("Users"),
                        url: "Users",
                        icon: "fa fa-users",
                        requiredPermissionName: PermissionNames.Pages_Users
                        )
                ).AddItem(
                    new MenuItemDefinition(
                        "About",
                        L("About"),
                        url: "About",
                        icon: "fa fa-info"
                        )
                );
    }
}

该文件中默认定义了Home、Tenants、Users、About四个菜单。注意观察的话,想必会注意到Home菜单设置了requiresAuthentication: true,即只有登陆后才会显示该菜单。Tenants和Users菜单设置了requiredPermissionName属性,即用户具有指定的权限时才显示菜单。About菜单没有限制,默认显示。
每一个菜单项都是一个MenuItemDefinition,其中主要包括Name(唯一名称),DisplayName(本地化显示名称),Url(菜单跳转),Icon(指定菜单图标)。
解释到这里,大家自己都可以依葫芦画瓢,新增菜单了。

2.添加[Task List]菜单项

AddItem(
  new MenuItemDefinition(
      "TaskList",
      L("Task List"),
      url: "Tasks/Index",
      icon: "fa fa-tasks",
      requiresAuthentication: true
  )

保存,刷新页面即可看到新增的[Task List]菜单了。


PS:之所以页面上会显示为[Task List],是因为我们并没有维护本地化资源文件。在对应的本地化配置文件中新增名为"Task List"的即可。比如在中文的本地化文件中添加
<text name="Task List" value="任务清单" />,重新启站点,将语言切换为中文。


二、Abp集成的导航菜单的代码结构

1.先来看看相关代码的类型依赖关系图


类型依赖关系图

分析发现,abp集成的导航菜单实际上是应用了组合设计模式。
其中MenuDefinition为根节点,MenuItemDefinition为树枝节点,其中MenuItemDefinition中也维护了一个List<MenuItemDefinition>的集合,当集合为空时,MenuItemDefinition即为树叶节点。

2.从图中可以看出,主要是由以下几部分组成:

  • MenuDefinition/MenuItemDefinition:菜单/菜单项定义。其中菜单项包括Name(唯一名称),DisplayName(本地化显示名称),Url(菜单跳转),Icon(指定菜单图标)。此外,可以通过指定RequiresAuthentication=true来限制菜单项只有对登录用户可见,同时也可以指定RequiredPermissionName来限定当用户有某个权限时菜单才可见。
  • UserMenu/UserMenuItem:封装了用于显示给用户的菜单/子菜单集合。
  • INavigationConfiguration/NavigationConfiguration:导航配置,维护了NavigationProvider的列表。
  • NavigationProvider:Provider模式(将api的定义和实现分离)。抽象类,定义了SetNavigation方法,在需要设置导航的项目中实现该类,并在对应的模块中PreInitialize方法中注册***NavigationProvider的实现。
  • INavigationManager/NavigationManager:其中接口中定义了一个Dictionary,用来存储应用程序中定义的所有菜单项,和一个MainMenu。注入了对INavigationConfiguration的引用,以便在NavigationManager中的Initialize方法遍历INavigationConfiguration配置的NavigationProvider列表进行菜单的初始化。
    IUserNavigationManager/UserNavigationManager:是对NavigationManager的一次封装。其中接口中定义了GetMenuAsync的重载方法,用来获取指定用户的菜单。
  • INavigationProviderContext/NavigationProviderContext:封装了INavigationManager的上下文类,用于传参。

三、Abp集成的导航菜单的具体实现

核心逻辑:NavigationManager遍历NavigationConfiguration中维护的NavigationProvider列表,并调用NavigationProvider实现的SetNavigation方法来完成导航菜单的初始化。

NavigationManager负责初始化菜单


NavigationManager.cs

NavigationConfiguration负责维护NavigationProvider的实现列表。


NavigationConfiguration.cs

具体的NavigationProvider的实现


xxxxNavigationProvider.cs

在对应的模块中注册具体的NavigtionProvider到INavigationConfiguration维护的列表中。


xxxxAbpWebModule.cs

UserNavigationManager对NavigationManager进行了进一步的封装,根据用户和权限去创建和获取菜单。


IUserNavigationManager.cs

在LayoutController中,通过注入对IUserNavigationManager的引用,来获取菜单,并由_TopMenu分部页进行最终呈现。

public class LayoutController : LearningMpaAbpControllerBase
    {
        private readonly IUserNavigationManager _userNavigationManager;
        private readonly ISessionAppService _sessionAppService;
        private readonly IMultiTenancyConfig _multiTenancyConfig;
        private readonly ILanguageManager _languageManager;

        public LayoutController(
            IUserNavigationManager userNavigationManager, 
            ISessionAppService sessionAppService, 
            IMultiTenancyConfig multiTenancyConfig,
            ILanguageManager languageManager)
        {
            _userNavigationManager = userNavigationManager;
            _sessionAppService = sessionAppService;
            _multiTenancyConfig = multiTenancyConfig;
            _languageManager = languageManager;
        }

        [ChildActionOnly]
        public PartialViewResult TopMenu(string activeMenu = "")
        {
            var model = new TopMenuViewModel
                        {
                            MainMenu = AsyncHelper.RunSync(() => _userNavigationManager.GetMenuAsync("MainMenu", AbpSession.ToUserIdentifier())),
                            ActiveMenuItemName = activeMenu
                        };

            return PartialView("_TopMenu", model);
        }
}

至此,我们完成了对导航菜单的梳理和总结。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 158,117评论 4 360
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 66,963评论 1 290
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 107,897评论 0 240
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,805评论 0 203
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,208评论 3 286
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,535评论 1 216
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,797评论 2 311
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,493评论 0 197
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,215评论 1 241
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,477评论 2 244
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 31,988评论 1 258
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,325评论 2 252
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 32,971评论 3 235
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,055评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,807评论 0 194
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,544评论 2 271
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,455评论 2 266

推荐阅读更多精彩内容

  • 发现 关注 消息 iOS 第三方库、插件、知名博客总结 作者大灰狼的小绵羊哥哥关注 2017.06.26 09:4...
    肇东周阅读 11,609评论 4 59
  • Android 自定义View的各种姿势1 Activity的显示之ViewRootImpl详解 Activity...
    passiontim阅读 170,563评论 25 707
  • 抖了一会。后面热,麻。过后,觉察到自己一个模式,心胸狭隘了,眼睛里只能盯着别人的缺点,看不到别人优点,不全面,整个...
    安心的心灵花园阅读 181评论 0 0
  • 2017年9月28日 D49阿尔法号+阿基米德舱+刘虹秀+打卡 今日任务: 收听晨间导读:再谈社会空间里的自我和他...
    伊秀儿阅读 160评论 0 0
  • 若只是喜欢,何必夸张成爱
    Besttime禁阅读 131评论 0 0