ASP.NET Core Blazor 路由解析
在Web应用程序开发中,URL是连接不同页面和功能的关键。它允许用户在应用的不同部分之间导航,实现组件间的交互。在ASP.NET Core MVC或ASP.NET WebForms中,我们通常使用<a>标签或服务器端重定向来实现页面跳转。那么,Blazor是如何处理页面导航的呢?
使用@page指令定义路由
Blazor框架内置了一个名为Router的组件,它负责处理应用程序内的路由。在Blazor应用项目的App.razor文件中,我们可以找到Router组件的配置:
<Router AppAssembly="@typeof(App).Assembly">
<Found Context="routeData">
<RouteView RouteData="@routeData" DefaultLayout="@typeof(MainLayout)" />
<FocusOnNavigate RouteData="@routeData" Selector="h1" />
</Found>
<NotFound>
<PageTitle>未找到</PageTitle>
<LayoutView Layout="@typeof(MainLayout)">
<p role="alert">抱歉,此地址不存在。</p>
</LayoutView>
</NotFound>
</Router>
要让一个Blazor组件能够被路由访问,需要在其文件顶部添加@page指令,并指定一个URL路径。例如,@page "/booklist"会将该组件映射到/booklist这个URL。在编译时,带有@page指令的Razor组件会被编译器自动添加[RouteAttribute]特性,该特性包含了组件的路由信息。
应用程序启动时,Router组件会扫描AppAssembly属性指定的程序集,收集所有带有[RouteAttribute]的组件及其路由信息。运行时,RouteView组件负责根据路由数据渲染相应的组件,并应用指定的布局。
如果组件没有显式指定布局(使用@layout指令),RouteView的DefaultLayout参数将用于指定一个默认布局。在.NET 6的Blazor项目模板中,通常默认使用Shared/MainLayout.razor作为应用的默认布局。
<RouteView RouteData="@routeData" DefaultLayout="@typeof(MainLayout)" />
当访问 /booklist 时,Booklist 组件将被渲染。需要注意的是,Router组件不直接处理URL的查询字符串部分。
自定义"未找到"页面
当用户访问的URL与任何已定义的路由不匹配时,Router组件会渲染<NotFound>节点内的内容。我们可以自定义这个部分来显示一个404错误页面或提供用户友好的提示信息。在App.razor文件中,找到<NotFound>节点并修改其内容:
<Router AppAssembly="@typeof(App).Assembly">
<Found Context="routeData">
<RouteView RouteData="@routeData" DefaultLayout="@typeof(MainLayout)" />
<FocusOnNavigate RouteData="@routeData" Selector="h1" />
</Found>
<NotFound>
<PageTitle>未找到</PageTitle>
<LayoutView Layout="@typeof(MainLayout)">
<h1>页面未找到!请检查URL是否正确。</h1>
<p role="alert">抱歉,此地址不存在。</p>
</LayoutView>
</NotFound>
</Router>
任何HTML片段或Blazor组件都可以放在<NotFound>节点中。如果在运行时访问一个不存在的URL(例如 /nonexistentpage),用户将看到我们自定义的"未找到"页面。
注意: 在浏览器地址栏手动输入URL并回车会触发一次完整的HTTP请求和页面重新渲染。而Blazor内部的导航则在客户端完成,不会刷新整个页面。
使用<a>标签进行导航
在Blazor中,标准的<a>标签同样支持用于页面内导航。当用户点击一个带有href属性的<a>标签时,Blazor会拦截该导航事件,并在客户端执行路由跳转,而不会发生页面刷新。
假设我们在Booklist.razor组件中需要一个链接来跳转到添加图书的页面:
@page "/booklist"
@using BlazorAppDemo.Models
@using Microsoft.EntityFrameworkCore
@inject IDbContextFactory<BookContext> dbFactory
<PageTitle>图书列表</PageTitle>
<h3>图书列表</h3>
<table class="table-responsive" width="90%">
<tr>
<td>名称</td>
<td>作者</td>
<td>价格</td>
<td>发布日期</td>
<td>库存</td>
<td>数量</td>
<td>操作</td>
</tr>
@foreach (var item in books)
{
<tr>
<td>@item.Name</td>
<td>@item.Author</td>
<td>@item.Price</td>
<td>@item.ReleaseDate.ToShortDateString()</td>
<td>@item.StockQty</td>
<td>@item.Qty</td>
<td><a href="/addbook">编辑</a></td>
</tr>
}
</table>
@code {
private static BookContext _context;
private List<Book> books = new List<Book>();
protected override async Task OnInitializedAsync()
{
_context = dbFactory.CreateDbContext();
books = await _context.Book.ToListAsync();
await base.OnInitializedAsync();
}
}
在这个例子中,列表中的每一项都包含一个"编辑"链接,其href指向/addbook。当用户点击这个链接时,Blazor会将页面导航到/addbook路由,而无需重新加载整个页面。这种客户端导航方式提供了更流畅的用户体验。