前言

最近写了多篇关于Source Generators的文章,发现它确实可以简化我们的部分开发工作。

这不,我又盯上了Blazor。

问题

默认的NavMenu.razor组件用于显示导航菜单,它的部分代码如下:

<div class="@NavMenuCssClass" @onclick="ToggleNavMenu"><ul class="nav flex-column"><li class="nav-item px-3"><NavLink class="nav-link" href="" Match="NavLinkMatch.All"><span class="oi oi-home" aria-hidden="true"></span> Home</NavLink></li><li class="nav-item px-3"><NavLink class="nav-link" href="counter"><span class="oi oi-plus" aria-hidden="true"></span> Counter</NavLink></li><li class="nav-item px-3"><NavLink class="nav-link" href="fetchdata"><span class="oi oi-list-rich" aria-hidden="true"></span> Fetch data</NavLink></li></ul>
</div>

这也就意味着,如果我们增加一个页面,就要修改一次NavMenu.razor组件,这当然是不合适的。

实现原理

我们查看obj\Debug\net5.0\Razor\Pages\Counter.razor.g.cs(编译时生成的中间文件),可以看到如下代码:

[Microsoft.AspNetCore.Components.RouteAttribute("/counter")]
public partial class Counter : Microsoft.AspNetCore.Components.ComponentBase

它其实对应源代码里的:

@page "/counter"

也就是说,只要我们遍历所有的Microsoft.AspNetCore.Components.RouteAttribute,获得路由信息放到List<Menu>即可。

具体实现代码如下:

[Generator]public class MenuGenerator : ISourceGenerator{private const string MenuClassText = @"
public class Menu
{public string Route { get; set; }public string Title { get; set; }
}";public void Initialize(GeneratorInitializationContext context){}public void Execute(GeneratorExecutionContext context){context.AddSource("Menu", SourceText.From(MenuClassText, Encoding.UTF8));var options = (context.Compilation as CSharpCompilation).SyntaxTrees[0].Options as CSharpParseOptions;var compilation = context.Compilation.AddSyntaxTrees(CSharpSyntaxTree.ParseText(SourceText.From(MenuClassText, Encoding.UTF8), options));var allClasses = compilation.SyntaxTrees.SelectMany(x => x.GetRoot().DescendantNodes().OfType<ClassDeclarationSyntax>());var sourceBuilder = new StringBuilder(@"
using System.Collections.Generic;
namespace MenuGenerator
{public static class NavHelper{public static IEnumerable<Menu> GetMenus(){return new List<Menu> {");foreach (var classDeclarationSyntax in allClasses){var routeAttribute = classDeclarationSyntax.AttributeLists.SelectMany(x => x.Attributes).FirstOrDefault(attr => attr.Name.ToString() == "Microsoft.AspNetCore.Components.RouteAttribute");if (routeAttribute != null){var routeArg = routeAttribute.ArgumentList.Arguments.First();var routeExpr = routeArg.Expression;var semanticModel = compilation.GetSemanticModel(classDeclarationSyntax.SyntaxTree);var route = semanticModel.GetConstantValue(routeExpr).ToString();if (route == @"/") continue;var title = classDeclarationSyntax.Identifier.ToString();sourceBuilder.Append($@"
new Menu{{ Route = ""{route}"", Title = ""{title}"" }},");}}sourceBuilder.Append(@"
};
}}
}");context.AddSource("Mapper", SourceText.From(sourceBuilder.ToString(), Encoding.UTF8));}}

使用示例

修改NavMenu.razor代码如下:

<div class="@NavMenuCssClass" @onclick="ToggleNavMenu"><ul class="nav flex-column"><li class="nav-item px-3"><NavLink class="nav-link" href="" Match="NavLinkMatch.All"><span class="oi oi-home" aria-hidden="true"></span> Home</NavLink></li>@foreach (var menu in MenuGenerator.NavHelper.GetMenus()){<li class="nav-item px-3"><NavLink class="nav-link" href="@menu.Route"><span class="oi " aria-hidden="true"></span> @menu.Title</NavLink></li>}</ul>
</div>

编译后可以看到自动生成的代码:

运行后测试,工作正常,成功!

结论

菜单信息还有许多地方需要扩展,比如顺序、图标、菜单名称等,这些可以通过添加自定义Attribute实现。

如果你觉得这篇文章对你有所启发,请关注我的个人公众号”My IO“,记住我!

Hello Blazor:(9)Source Generators生成导航菜单相关推荐

  1. 使用vue-router自动生成导航菜单

    当我们选用ElementUI作为页面开发的组件库,并打算创建一个如下的菜单表项: 如果我们采用 ElementUI 库中的 el-menu 组件来实现的话,效果会很不错,但是代码的画风可能是这样的: ...

  2. 使用VueRouter自动生成导航菜单

    我们在搭建Web的后台管理系统时,会选择 ElementUI 进行快速搭建,但是在某些场景下,单纯的使用组件是不能满足要求的. 因为需求是在不断增加,不断变化的,如果像 ElementUI 给的示例去 ...

  3. 在 C# 中生成代码的四种方式——包括.NET 5中的Source Generators

    Microsoft在最新的C#版本中引入了Source Generator.这是一项新功能,可以让我们在代码编译时生成源代码.在本文中,我将介绍四种C#中的代码生成方式,以简化我们的日常工作.然后,您 ...

  4. 究竟是什么可以比反射还快实现动态调用?| Source Generators版

    前言 最近在公众号上看到一篇文章<究竟是什么可以比反射还快实现动态调用?>,它使用的是Newbe.ObjectVisitor,基于C#表达式树访问一个普通class的所有属性和对应的值,可 ...

  5. element ui 菜单 动态生成 导航

    1. 利用饿了么ui 的 导航菜单组件 (el-menu)来结合 后台返回的 菜单数组进行循环嵌套. 2.看如下代码 <el-menu:default-active="activeIn ...

  6. 来自数据库的MVC 6动态导航菜单

    目录 目标 介绍 使用的组件 创建Web项目 迁移 数据服务 导航菜单 接下来是什么 结论 Download source code - 977.3 KB 目标 几年前,我不得不从数据库加载导航菜单并 ...

  7. BootstrapBlazor实战 Menu 导航菜单使用(2)

    接上篇: B08. BootstrapBlazor实战 Menu 导航菜单使用(1) 实战BootstrapBlazorMenu 导航菜单的使用, 以及整合Freesql orm快速制作菜单项数据库后 ...

  8. 弧形背景html,JS实现带圆弧背景渐变效果的导航菜单代码

    本文实例讲述了JS实现带圆弧背景渐变效果的导航菜单代码.分享给大家供大家参考.具体如下: 这是一款效果个性的JS+CSS导航菜单,鼠标经过时出现有趣弧形背景,实际上,这里用CSS调用了背景,用Java ...

  9. 033_NavMenu导航菜单

    1. NavMenu导航菜单 1.1. NavMenu导航菜单为网站提供导航功能的菜单. 1.2. Menu Attribute 参数 说明 类型 可选值 默认值 mode 模式 string hor ...

最新文章

  1. 【Qt】Qt再学习(四):Editable Tree Model Example
  2. C#如何打开一个窗体,同时关闭该窗体
  3. bootstrap栅格分5等分
  4. anaconda 历史版本_【windows】下Anaconda详细安装过程
  5. java学习_java学习原理篇|java程序运行套路
  6. 随记一个C的毫秒级群PING
  7. [官方] mysql 性能优化文档(中英文自译)
  8. 逐步解析:杨辉三角(C语言)
  9. Flutter CustomScrollView实现的一个经典滑动折叠头部图片的效果
  10. mybatis-generator扩展教程系列 -- 自定义配置参数修改DAO,Mapper文件后缀
  11. 地理加权回归GWR4.0软件下载与使用
  12. 《史蒂夫·乔布斯传》(Steve Jobs)官方正式中文版高清PDF
  13. 找个网页游戏插件开发团队
  14. 泛微协同办公e-cology9.0的Ecode二次开发实例说明
  15. 思维导图:亿图的部分使用方法
  16. 如何复盘已搭建的会员积分系统
  17. HTML动画滑动图片特效
  18. Resultful API的拦截(过滤器——Filter)
  19. 数字通信调制方式的误码率matlab仿真,包括OOK,PRK,FSK以及QAM
  20. “Android开发3年老板嫌我工资高,把我辞了

热门文章

  1. ISA Server服务器故障恢复一例系统盘符更换之后的应对方法
  2. jquery对json的各种遍历
  3. webpack常用配置
  4. 《算法导论》读书笔记--第1、2章课后题 (转)
  5. ElasticSearch远程随意代码运行漏洞(CVE-2014-3120)分析
  6. 剑指offer编程题Java实现——面试题3二维数组中的查找
  7. xml.query() 实例演示
  8. CRM学习笔记(一)
  9. 061_Apex 异常捕捉
  10. oracle sqlplus使用