James: 转载技术社区中一位朋友最新的文章,介绍自己为公司的 WebForm 遗留系统使用 Blazor 重写前端 UI 的经历。
什么是Blazor组件
Blazor 应用是使用 Razor 组件构建的。组件是用户界面 (UI) 的自包含部分,具有用于启用动态行为的处理逻辑。组件可以嵌套、重复使用、在项目间共享,并可在 MVC 和 Razor Pages 应用中使用。
以上是官方文档给出的定义。实际在工程上,Blazor组件和其他Web前端框架组件一样,包括HTML、CSS和代码三个部分,只是这里的“代码”特指C#语言,而非最常见的JavaScript。
让我们先看一下官方文档给出的例子,创建一个razor文件Dialog.razor:
<div class="card" style="width:22rem"><div class="card-body"><h3 class="card-title">@Title</h3><p class="card-text">@ChildContent</p><button @onclick="OnYes">Yes!</button></div>
</div>@code {[Parameter]public RenderFragment ChildContent { get; set; }[Parameter]public string Title { get; set; }private void OnYes(){Console.WriteLine("Write to the console in C#! 'Yes' button selected.");}
}
这就是一个组件了。这个Dialog组件封装了:
一个允许外部传递值(Title属性)的标题(h3标签)
一个允许外部传入子组件的段落(p标签)
一个点击后触发OnYes方法的按钮(button标签)
div标签及样式
这个组件也展示了razor标记语言的特点,在HTML模板里,‘@’标记可以将控件的数据与C#代码的属性进行双向绑定;控件的事件与C#函数的绑定也是类似。这种数据和事件绑定的方式,在三大前端框架的应用中,也不陌生(Angular开发者可能最为亲切)。
注意到p标签里的内容,ChildContent表示一个子组件,与当前的组件形成嵌套。而对应的C#类型则是RenderFragment,这是一个非常重要的类型,是开发模板化组件的基础。官方提供了一些使用案例,但若要从实际应用的角度去理解,我还是建议去参考一些开源组件项目里的组件实现,这里暂不赘述。
我们再看一下如何使用它:
@page "/"<h1>Hello, world!</h1><p>Welcome to your new app.</p><Dialog Title="Learn More">Do you want to <i>learn more</i> about Blazor?
</Dialog>
这段代码的效果如下:
可以看到页面下方就是封装了html标签的Dialog组件,其中@page用来表示当前页面的路由。
官方给的这个案例,在我看来是花了点心思的:它的结构很简单,并不难理解,却充分展示了Blazor组件的基本面貌和Razor语言的基本特点,又涉及到了Blazor组件十分灵活同时开发上限很高的模板化开发,后续等初学者接触到“组件模板化”的文档时,起码不会一无所知了。
本地内置组件
Blazor框架官方内置了一些组件。其中AuthorizeView组件和Route组件是最值得关注的。
涉及到敏感数据的后台管理系统,肯定要有一套认证授权的机制。AuthorizeView组件经常被用在Layout组件里,来区别显示认证前后的UI元素。这个组件的实际应用,将在系列的后文中具体介绍。
Route组件则更基础了,SPA框架当然需要自己的一套路由规则;另外还要处理404的情况。这些都在Route组件(写在App.razor文件中)里为开发者提供了。
<Router AppAssembly="@typeof(Program).Assembly"><Found Context="routeData"><RouteView RouteData="@routeData" DefaultLayout="@typeof(MainLayout)" /></Found><NotFound><p>Sorry, there's nothing at this address.</p></NotFound>
</Router>
另外,Blazor提供了一个默认布局的MainLayout组件,由项目模板创建。但本质上它只是方便开发者理解如何在Blazor中使用布局。布局组件当然可以自定义名称和内容,我们可以在页面里使用@layout指令,来指定页面具体使用哪一个布局组件。
@page "/"
@layout CustomLayout<div>...</div>
其他组件,往往有更好的第三方开源组件,在功能和UI风格上可以取代,本文不特别介绍。内置组件的官方文档还是比较细致的,因此本文只略作指引,有兴趣的读者可以细读文档。
第三方开源组件
在组件式开发流行的今天,任何一个前端框架想要获取开发者的青睐,开源社区的支持必不可少。甚至我认为Blazor的推广和普及,开源组件库首当其冲,属于社区生态的基础设施。Blazor发展至今,已经有了多个第三方开源组件项目,基本涵盖了市面上比较常见的UI组件:Ant Design/Bootstrap/Material UI/Element UI/……
开发Blazor应用时,选择什么样的UI组件和风格,本就是“萝卜青菜,各有所爱”。我最终选择了Ant-Design组件来开发后台,这里仅提几点个人的意见,供读者参考:
Ant Design源自阿里优秀的企业级开源UI设计,前端三大框架均有对应的组件实现。Blazor实现的原型来自Ant Design React。
Ant-Design-Blazor项目的更新周期较短,issue和开发团队的活跃度较高——意味着个人的意见更容易得到反馈,bug更快地得到修复,新功能更快地落实和发布。
Ant-Design-Blazor项目是较早一批被Blazor官方在技术大会上提及的开源项目之一——意味着项目已经得到一段时间的检验。
项目由国内开发者(Microsoft MVP)发起,在历史参与者中也有不少国内开发者,因此中文文档比较完善,对其他国内应用开发者的问题解答和技术支持也比较到位。
成熟的开源组件,可以带来巨大的开发效率提升。举一个非常简单的例子:使用Ant-Design-Blazor的Result组件,实现一个更优雅的404提示页面,来替换上面展示的官方Demo里的404(NotFound)页面。
先创建一个MyNotFound.razor文件,代码如下:
@using AntDesign;<div style="margin:40px"><Result Status="404"Title="404"SubTitle="您要访问的页面不存在!"Extra="extra" />
</div>@code {RenderFragment extra =@<strong style="font-size:20px">回到 <a href="/home">首页</a></strong>;
}
然后在上文提到的Route组件里替换NotFound组件的内容即可:
<Router AppAssembly="@typeof(Program).Assembly"><Found Context="routeData"><RouteView RouteData="@routeData" DefaultLayout="@typeof(MainLayout)" /></Found><NotFound><MyNotFound /></NotFound>
</Router><AntContainer />
让我们故意访问一个不存在的路由,看一下效果:
还不错吧?比只显示一行文字好看多了,而且并不需要费多少心思找素材和写代码。
目前Ant-Design-Blazor项目正发起一个讨论,欢迎开发者们分享基于Antd组件实现的产品:Who is using Ant Design Blazor in production? · Discussion #1693 · ant-design-blazor/ant-design-blazor。另外,开发团队还增加了一个开箱即用的模板项目:ant-design-blazor/ant-design-pro-blazor。该项目既可以作为参考教材,又可以作为项目生成的基础。
当然,对任何开源Blazor UI组件项目来说,项目维护活跃、较完善的(中文)文档支持、开箱即用的模板项目,都会得到更多用户的信任,从而吸引更多的用户使用。例如,在我个人眼中,BootstrapBlazor和MatBlazor也是出类拔萃的竞争者。
结束语
在本系列接下来的文章里,我将围绕一个基于内置组件和Ant-Design-Blazor组件开发的后台Demo为例,具体介绍Blazor框架的实践经验。让我们先从正常用户访问后台的第一个页面——登录页面开始,下一篇文章,再会!