Hello Blazor:(9)Source Generators生成导航菜单

前言

最近写了多篇关于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“,记住我!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/299536.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

你绝对没想过原来数学家这么流氓,一言不合就进行暴力证明

全世界只有3.14 % 的人关注了青少年数学之旅1最经典的“无字证明”1989 年的《美国数学月刊》&#xff08;American Mathematical Monthly&#xff09;上有一个貌似非常困难的数学问题&#xff1a;下图是由一个个小三角形组成的正六边形棋盘&#xff0c;现在请你用右边的三种&a…

面试阿里被问到JVM,不逼逼赖赖,直接盘给面试官看!!!

面试阿里被问到JVM&#xff0c;不逼逼赖赖&#xff0c;直接盘给面试官看&#xff01;&#xff01;&#xff01;概述JVM体系结构类加载机制类加载器类加载过程双亲委派机制全盘负责委托机制打破双亲委派机制自定义类加载器实现JVM运行时数据区程序计数器虚拟机栈本地方法栈堆方法…

数学图形(1.20)N叶草

有N个叶子的草 相关软件参见:数学图形可视化工具,使用自己定义语法的脚本代码生成数学图形.该软件免费开源.QQ交流群: 367752815 vertices 1000 t from 0 to (2*PI) r 10 n rand_int2(3, 10) p 1 cos(n*t) sin(n*t)^2 x p*cos(t) y p*sin(t) N叶草面_1 vertices D1:5…

虚拟主机网速测试

ping 命令简单测试网速&#xff0c;我来测一下自己刚买的虚拟主机废话少说&#xff0c;上图&#xff1a;&#xff08;看不清的&#xff0c;点击图片看大图&#xff09;A.中国电信&#xff08;学校的光缆&#xff0c;教师办公专用至少30M&#xff0c;具体数字不清楚&#xff0c;…

Visual Studio 2022 Preview 3和2019 16.11发布

Visual Studio 2022 Preview 3 主要特点个人和团队生产力附加到进程改进新项目设计器黑暗主题提升开发现代应用远程测试新的JavaScript和TypeScript项目类型在指尖上的创新诊断分析同时使用多个GIT存储库详情请参考&#xff1a;https://devblogs.microsoft.com/visualstudio/vi…

获取DataTable字段唯一值(DISTINCT)

///<summary>///将所选字段的唯一值复制到一个新的 DataTable。 ///<para>如果字段包含 NULL 值&#xff0c;目标表中的记录还包含 NULL 值</para>///</summary>///<param name"sourceTable">源数据表</param>///<pa…

梦真的是反的 | 今日最佳

全世界只有3.14 % 的人关注了青少年数学之旅&#xff08;图源神店通缉令&#xff0c;侵权删&#xff09;

面试官问:怎么保证线程安全在对象内存分配过程中不出问题?emmmm 让我想想

Java一门面向对象的语言&#xff0c;在Java中使用的对象都需要被创建出来&#xff0c;在Java中创建一个对象的方法有很多种&#xff0c;但对象在创建过程中都需要进行内存分配。Java对象内存分配过程保证线程安全&#xff0c;对象的内存分配过程就必须进行同步控制。 对象的内…

.NET 6 预览版 7:新功能已完成 ,将专注于改进

.NET 团队的项目经理 Richard Lander在宣布 .NET 6 Preview 7 时说&#xff1a;“这是 .NET 预览的又一季的结束。”, 中文翻译&#xff1a;.NET 6 预览版 7 发布——最后一个预览版。.NET 6.0 是微软统一 .NET 平台的一个重要版本和第一个 LTS&#xff08;长期支持&#xff09…

要做好性能测试,该掌握些什么?

1. 精通性能测试的基本概念&#xff0c;过程&#xff0c;方法论&#xff0c;了解性能工程&#xff1b; 2. 精通1个商业性能测试工具1个开源性能测试工具&#xff0c;知道工具可以做什么&#xff0c;不可以做什么&#xff0c;以及工具使用中常见的问题和解决思路&#xff1b; 3.…

do...while(0)的妙用

在C中&#xff0c;有三种类型的循环语句&#xff1a;for, while, 和do...while&#xff0c; 但是在一般应用中作循环时&#xff0c; 我们可能用for和while要多一些&#xff0c;do...while相对不受重视。但是&#xff0c;最近在读我们项目的代码时&#xff0c;却发现了do...whil…

Windows server 2003 CA配置(一)

CA:Certificate Authority,证书权威机构,也称为证书颁发机构或认证中心)是PKI中受信任的第三方实体.负责证书颁发、吊销、更新和续订等证书管理任务和CRL发布和事件日志记录等几项重要的任务。首先&#xff0c;主体发出证书申请&#xff0c;通常情况下&#xff0c;主体将生成密…

js堆和栈的区别_几个例子理解不同数据类型的堆栈内存处理

如有错误烦请指正js代码的运行环境浏览器 内核(引擎)nodewebview(hybrid&#xff0c;嵌入到手机app里面&#xff0c;在app里面运行)...下面通过几个例子理解不同数据类型的堆栈内存处理js如何运行(示例1)var a 12;var b a;b 13;console.log(a);浏览器能够运行js代码&#xf…

世界上没有后悔药,时间匆匆,从关注它们开始......

全世界只有3.14 % 的人关注了青少年数学之旅在这个资讯丰富且易获取的时代&#xff0c;越来越多的人不愿意花时间阅读书籍&#xff0c;碎片化阅读成了主流。人们获取的东西多而杂&#xff0c;很难系统、全面。海量信息对人是冲击&#xff0c;更是诱惑。谁不想了解天下奇闻&…

什么?面试官问我Java内存模型!这不得给我加薪?

内存模型的基础 通信  线程之间以何种机制来交换信息 共享内存  隐式通信消息传递  显示通信 同步  程序中用于控制不同线程间操作,发生的相对顺序的机制 共享内存  显式同步消息传递  隐式同步 Java线程线程之间是通过共享内存的方式实现通信的. 内存模型的抽…

使用 Blazor 开发内部后台(四):基于Card组件快速搭建导航首页

James: 本系列为大家介绍如何使用 Blazor 来开发管理后台&#xff0c;有兴趣的朋友欢迎跟着实验&#xff0c;体验 Blazor 开发的高效与乐趣。本系列目录&#xff1a;使用 Blazor 开发内部后台&#xff08;一&#xff09;&#xff1a;认识Blazor使用 Blazor 开发内部后台&#x…

《西河大鼓——酒色财气》(艳桂荣音配像)

《西河大鼓——酒色财气》&#xff08;唱词文本&#xff09;[url]http://qinyezhai.blog.51cto.com/179831/106820[/url]这是艳桂荣先生根据1998年本人录音于2000年由本人配像&#xff0c;时年72岁&#xff01;转载于:https://blog.51cto.com/qinyezhai/106822

LOOP WITH CONTROL 用法

LOOP - WITH CONTROL Syntax 语法LOOP [AT itab INTO wa [CURSOR top_line] [FROM n1] [TO n2]] WITH CONTROL contrl. ... ENDLOOP. Variants: 变式1. LOOP WITH CONTROL contrl. 2. LOOP AT itab CURSOR cur INTO wa [CURSOR top_line] [FROM n1] [TO n2] …

位操作

1. 改变符号&#xff1a;取反1 2. 与0异或保持不变&#xff0c;与-1(0xffffffff)异或相当于取反。 3. 负数右移可以认为是补符号位&#xff08;当然也有机器不是这样子&#xff09;。负数右移31位就是-1. 1 int sign(int n) {2 return ~n 1;3 }4 5 int abs(int n) {6 …

2020年,朋友圈的正确打开方式!

全世界只有3.14 % 的人关注了青少年数学之旅各位读者朋友们大家好 我是你们的小伙伴上流君我们开始不定期做互推了不是广告&#xff0c;根据兴趣关注感谢理解与支持ღ( &#xff65;ᴗ&#xff65; )比心有些人&#xff0c;生活离不开朋友圈。朋友圈是他们展示自我、观察世界的…