Hello Blazor:(9)Source Generators生成导航菜单
生活随笔
收集整理的這篇文章主要介紹了
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“,記住我!
總結
以上是生活随笔為你收集整理的Hello Blazor:(9)Source Generators生成导航菜单的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 如何禁用 ASP.NET 网站的所有的
- 下一篇: Visual Studio 2022 P