Blazor 路由及导航开发指南

翻译自 Waqas Anwar 2021年4月2日的文章 《A Developer’s Guide To Blazor Routing and Navigation》 [1]

检查传入的请求 URL 并将它们导航到对应的视图或页面是每个单页应用程序 (SPA) 框架的基本功能。Blazor Server 和 WebAssembly 应用程序也同样支持使用一些内置组件和服务进行路由。在本教程中,我将向您介绍在 Blazor 应用程序中实现路由所需了解的所有内容。

Blazor 应用程序中的路由配置

在开始为不同的 Blazor 组件/页面创建路由之前,我们需要了解如何将 Blazor Server 应用程序集成到 ASP.NET Core Endpoint 路由中。Blazor Server 应用程序通过 SignalR 连接与客户端进行通信,为了接受 Blazor 组件传入的连接,我们在 Startup.cs 文件的 Configure 方法中调用了 MapBlazorHub 方法,如下所示:

app.UseEndpoints(endpoints =>
{endpoints.MapBlazorHub();endpoints.MapFallbackToPage("/_Host");
});

默认配置将所有请求都转发到一个 Razor 页面,该页面扮演 Blazor Server 应用程序服务端主机的角色。按照惯例,该主页是 _Host.cshtml,它位于应用程序的 Pages 文件夹中。该主文件中指定的路由称之为应急路由,在路由匹配中具有极低的优先级,这意味着当没有其他路由匹配时,才会使用该路由。

Blazor 路由组件介绍

Router[2] 组件是 Blazor 中的内置组件之一,用在 Blazor 应用程序的 App 组件之中。该组件启用了 Blazor 应用程序中的路由,并提供与当前导航状态相对应的路由数据。它拦截传入的请求并呈现与请求 URL 相匹配的页面。

<Router AppAssembly="@typeof(Program).Assembly" PreferExactMatches="@true"><Found Context="routeData"><RouteView RouteData="@routeData" DefaultLayout="@typeof(MainLayout)" /></Found><NotFound><LayoutView Layout="@typeof(MainLayout)"><p>Sorry, there's nothing at this address.</p></LayoutView></NotFound>
</Router>

下表显示了 Router 组件的属性。

当编译 Blazor 组件 (.razor) 时,它们生成的 C# 类会保存在 obj\Debug\net5.0\Razor\Pages 文件夹中。

如果您打开任意一个已编译的文件,将会注意到在编译之后,所有带有 @page 指令的组件都生成了一个带有 RouteAttribute 特性的类。

当应用程序启动时,会扫描通过 AppAssembly 属性指定的程序集,从所有指定了 RouteAttribute 特性的类中收集路由信息。

<Router AppAssembly="@typeof(Program).Assembly" PreferExactMatches="@true">

如果您创建了独立的组件类库,并希望应用程序从这些程序集中扫描和加载路由,那么您可以使用 AdditionalAssemblies 属性来接受一个 Assembly 对象集合。

下面是一个从定义在组件类库中的两个可路由组件(Component1 和 Component2)加载路由信息的示例。

<Router AppAssembly="@typeof(Program).Assembly" PreferExactMatches="@true"AdditionalAssemblies="new[] { typeof(Component1).Assembly, typeof(Component2).Assembly }"> 
</Router>

在运行时,RouteView 组件从 Router 接收 RouteData 以及任意路由参数,并使用组件中定义的布局渲染指定的组件。如果未定义布局,则使用 DefaultLayout 属性指定的布局。默认的布局通常是 Shared 文件夹中的 MainLayout 组件,不过您也可以创建并指定一个自定义布局。

<RouteView RouteData="@routeData" DefaultLayout="@typeof(MainLayout)" />

Found 模板用于在找到匹配的路由时显示其内容,正如您在下图中所看到的那样,其中找到了一个匹配路由,并在浏览器中呈现了一个 Counter 页面。

NotFound 模板用于在没有找到匹配的路由时显示内容。默认情况下,NotFound 模板仅显示一条消息,如下面的截图所示。

我们还可以创建自定义错误的布局和页面,以显示自定义错误页面。让我们在 Shared 文件夹中创建一个新的名为 ErrorLayout.razor 的自定义布局。

ErrorLayout.razor

@inherits LayoutComponentBase<main role="main" class="container"> <div class="text-center">@Body</div> 
</main>

然后将 LayoutView 组件的 Layout 属性改为 ErrorLayout,并将 LayoutView 里的内容修改如下:

<Router AppAssembly="@typeof(Program).Assembly" PreferExactMatches="@true"><Found Context="routeData"><RouteView RouteData="@routeData" DefaultLayout="@typeof(MainLayout)" /></Found><NotFound><LayoutView Layout="@typeof(ErrorLayout)"><h1 class="display-1">404</h1><h1 class="display-4">Not Found</h1><p class="lead">Oops! Looks like this page doesn't exist.</p></LayoutView></NotFound>
</Router>

现在,如果您在浏览器中运行应用程序,并尝试访问一个未在应用中任何位置指定过的 URL,那么您将会看到一个自定义的 404 错误页面,如下所示。

所有 Blazor 应用程序都应将 PreferExactMatches 特性显式地设置为 @true,以便路由匹配更倾向于精确匹配,而不是通配符匹配。根据 Microsoft 官方文档,此特性从 .NET 6 开始将不可用,路由器将总是更倾向于精确匹配。

定义路由、参数和约束

在我们学习如何为 Blazor 组件定义路由之前,我们需要确保下面的 base 标签在每个页面都可用,以便正确地解析 URL。如果创建的是 Blazor Server 应用程序,那么您可以将此标签添加到 Pages/_Host.cshtml 文件的 head 部分,如果是 Blazor WebAssembly 应用程序,则可以将此标签添加到 wwwroot/index.html 文件中。

<base href="~/" />

要定义路由,我们可以使用 @page 指令,如下面的 Counter 组件示例所示。

@page "/counter"<h1>Counter</h1><p>Current count: @currentCount</p><button class="btn btn-primary" @onclick="IncrementCount">Click me</button>@code {private int currentCount = 0;private void IncrementCount(){currentCount++;}
}

现在我们就可以使用 /counter URL 访问 Counter 组件了。

我们还可以使用多个 @page 指令定义多个路由模板,如下面例所示。

@page "/counter"
@page "/mycounter"

这意味着现在也可以使用 /mycounter URL 访问同一个 Counter 组件:

使用路由参数将数据从一个页面传递到另一个页面是十分常见的做法,Blazor 路由模板支持路由参数。路由参数名称不区分大小写,一旦我们定义了路由参数,路由器就会自动填充对应的具有相同名称的组件属性。例如,在下面的代码片段中,我们在组件中定义了一个路由参数 title,并创建了一个对应的属性 Title。此属性将自动使用路由参数文本的值填充。然后,我们在 h1 元素中显示 Title 属性作为页面的标题。

@page "/counter/{title}"<h1>@Title</h1><p>Current count: @currentCount</p><button class="btn btn-primary" @onclick="IncrementCount">Click me</button>@code {private int currentCount = 0;[Parameter]public string Title { get; set; }private void IncrementCount(){currentCount++;}
}

运行应用程序,并尝试在地址栏中 /counter/ 之后指定任意的字符串,您将看到路由参数的值会显示为页面标题。

我们还可以定义可选的路由参数,如下例所示,其中 title 是可选参数,因为在此参数名称后面带有问号 (?)。假如我们不提供此路由参数的值,该参数将在 OnInitialized 方法中使用默认值 Counter 进行初始化。

@page "/counter/{title?}"<h1>@Title</h1><p>Current count: @currentCount</p><button class="btn btn-primary" @onclick="IncrementCount">Click me</button>@code {private int currentCount = 0;[Parameter]public string Title { get; set; }protected override void OnInitialized(){Title = Title ?? "Counter";}private void IncrementCount(){currentCount++;}
}

Blazor 还支持路由约束,在路由上强制类型匹配。在下面的代码片段中,我创建了一个 int 类型的路由参数 start,这意味着现在我只能为此路由参数提供整数值。计数器现在将以路由参数中指定的值开始计数。

@page "/counter/{start:int}"<h1>Counter</h1><p>Current count: @Start</p><button class="btn btn-primary" @onclick="IncrementCount">Click me</button>@code { [Parameter]public int Start { get; set; }private void IncrementCount(){Start++;}
}

在浏览器中运行应用程序,并在 URL 中指定任一整数值,比如 /counter/4,您会看到计数器将以该起始值递增。

下表显示了 Blazor 路由约束支持的类型。

还可以定义多个路由参数,如下例所示,我们将 start 和 increment 定义为 int 类型的参数。

@page "/counter/{start:int}/{increment:int}"<h1>Counter</h1><p>Current count: @Start</p><button class="btn btn-primary" @onclick="IncrementCount">Click me</button>@code { [Parameter]public int Start { get; set; }[Parameter]public int Increment { get; set; }private void IncrementCount(){Start+=Increment;}
}

如下所示,运行应用程序并在 URL 地址中指定 start 和 increment 的值,您会注意到,当您每次点击 Click me 按钮时,计数器不仅会以数字 2 开始计数,而且会以 3 递增。

Blazor NavigationManager 服务概述

NavigationManager 服务允许我们在 C# 代码中管理 URI 和导航。NavigationManager 类具有以下常见的属性、方法和事件。

让我们来创建一个页面,查看一下以上属性和方法的一些实际行为。创建一个新的 Blazor 组件并使用 @inject 指令注入 NavigationManager 服务。尝试在页面上打印出 Uri 和 BaseUri 属性,来查看一下它们返回的是什么类型的 URI。

@page "/navigationmanager"
@inject NavigationManager nvm<h3>Navigation Manager</h3>
<br /><p>@nvm.Uri</p>
<p>@nvm.BaseUri</p>

运行应用程序,您将在浏览器中看到类似以下内容的输出。Uri 属性显示当前页面的绝对 URI,而 BaseUri 属性显示当前的基 URI。

在页面上添加两个按钮 Home Page 和 Counter Page,并在 @code 代码块中添加它们的 onclick 事件处理方法。在事件处理方法中,我们可以在 C# 代码中使用 NavigateTo 方法将用户重定向到其它的 Blazor 组件。

@page "/navigationmanager"
@inject NavigationManager nvm<h3>Navigation Manager</h3>
<br /><p>@nvm.Uri</p>
<p>@nvm.BaseUri</p><button class="btn btn-primary" @onclick="GoToHome">Home Page
</button><button class="btn btn-primary" @onclick="GoToCounter">Counter Page
</button>@code {private void GoToHome(){nvm.NavigateTo("/");}private void GoToCounter(){nvm.NavigateTo("counter");}
}

运行应用程序并试着点击这两个按钮,将按预期的那样,您可以导航到主页和计数器页面。

如果不想以编程方式处理导航,而想在 HTML 中生成超链接,则可以使用 Blazor NavLink 组件。NavLink 组件类似于 HTML 中的 <a> 元素,具有一些很酷的功能。如果 NavLink 的 href 特性值与当前的 URL 相匹配,则会自动切换该元素的 active CSS 类(class)。这就使得我们可以在当前选中的链接上应用不同的样式。您可以在 Shared/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>

NavLink 组件还有一个 Match 属性,可以设置为以下选项之一:

  • NavLinkMatch.All:指定当 NavLink 与整个当前 URL 匹配时应处于活动状态。

  • NavLinkMatch.Prefix(默认值):指定当 NavLink 与当前 URL 的任意前缀匹配时应处于活动状态。

Match 属性:获取或设置一个值,该值表示 URL 匹配行为。

总结

在本教程中,我尝试介绍 Blazor 应用程序中的多种路由功能,还介绍了开发者可用的与路由相关的一些组件和服务。我希望您现在能够更熟练地定义路由、参数和约束。如果您喜欢本教程,请与他人分享以传播知识。

相关阅读:

  • Blazor Server 和 WebAssembly 应用程序入门指南

  • Blazor 组件入门指南

  • Blazor 数据绑定开发指南

  • Blazor 事件处理开发指南

  • Blazor 组件之间使用 EventCallback 进行通信

  • Blazor 路由及导航开发指南(本文)


相关链接:

  1. https://www.ezzylearning.net/tutorial/a-developers-guide-to-blazor-routing-and-navigation A Developer’s Guide To Blazor Routing and Navigation ↩︎

  2. https://docs.microsoft.com/zh-cn/dotnet/api/microsoft.aspnetcore.components.routing.router ↩︎

作者 :Waqas Anwar
译者 :技术译民
出品 :技术译站(https://ITTranslator.cn/)

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

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

相关文章

超详细图解!【MySQL进阶篇】SQL优化-索引-存储引擎

1. Mysql的体系结构概览 整个MySQL Server由以下组成 Connection Pool : 连接池组件Management Services & Utilities : 管理服务和工具组件SQL Interface : SQL接口组件Parser : 查询分析器组件Optimizer : 优化器组件Caches & Buffers : 缓冲池组件Pluggable Storag…

数据之美

数据是抽象的&#xff0c;尤其是海量数据&#xff0c;人的大脑很难直接对大量数据进行分析并获得印象&#xff0c;然而从另一个角度看&#xff0c;数据也可以异常美丽&#xff0c;人们设计了很多工具&#xff0c;让枯燥的数据图形化&#xff0c;本文介绍了50个数据图形化工具&a…

一个孩子能长大成人到底有多不容易? | 今日最佳

全世界只有3.14 % 的人关注了青少年数学之旅(图源警民直通车-上海&#xff0c;侵权删&#xff09;

差距50倍!为什么Web API第一次执行这么慢?

前言新建一个ASP.NET Core Web API项目&#xff0c;使用命令行方式启动&#xff0c;连续发送多次请求。从下图的时间线可以发现&#xff0c;第一次执行&#xff08;116ms&#xff09;比后面的&#xff08;2ms&#xff09;慢了很多:在这100多ms中&#xff0c;Web API到底做了些什…

Exchange服务器系列课程之四--管理Exchange收件人

前面已经讨论了Exchange的安装&#xff0c;今天我们来讨论一下Exchange服务器的用户管理。管理Exchange的工具在第二篇文章已经讨论过了&#xff0c;这里不再阐述。Exchange中的收件人对象有三种&#xff1a;用户&#xff0c;组&#xff0c;联系人。我们可以为收件人对象启用邮…

动力强劲的星型发动机,为何不用在汽车上呢?

全世界只有3.14 % 的人关注了青少年数学之旅星型发动机嘚瑟的模样&#xff0c;一定让人过目不忘——对&#xff0c;虽然它看起来妖娆&#xff0c;但动力却十分强劲。那它为什么没在汽车上普及呢&#xff1f;我们一起来看看&#xff01;什么是星型发动机星型发动机&#xff0c;顾…

超详细图解!【MySQL进阶篇】存储过程,视图,索引,函数,触发器

超详细图解&#xff01;【MySQL进阶篇】存储过程,视图,索引,函数,触发器1.1 下载Linux 安装包1.2 安装MySQL1.3 启动 MySQL 服务1.4 登录MySQL2\. 索引2.1 索引概述2.2 索引优势劣势2.3 索引结构2.3.1 BTREE 结构2.3.3 BTREE 结构2.3.3 MySQL中的BTree2.4 索引分类2.5 索引语法…

.Net Core with 微服务 - 分布式事务 - 2PC、3PC

最近比较忙&#xff0c;好久没更新了。这次我们来聊一聊分布式事务。在微服务体系下&#xff0c;我们的应用被分割成多个服务&#xff0c;每个服务都配置一个数据库。如果我们的服务划分的不够完美&#xff0c;那么为了完成业务会出现非常多的跨库事务。即使按照 DDD 的原则来切…

2019优质公众号大盘点,果断收藏了慢慢看吧 ~

全世界只有3.14 % 的人关注了青少年数学之旅又到年底了啦&#xff0c;也到了一年一度的年底盘点时间。那么2019年&#xff0c;又有哪些优质公众号崭露头角呢&#xff1f;本期将为您盘点几个优质公众号&#xff0c;总有一个刷屏过你的朋友圈&#xff01;长按二维码&#xff0c;选…

让未备案的网站先飙起来

让未备案的网站先飙起来作者&#xff1a;田逸&#xff08;sery163.com&#xff09;国人在技术方面的创新能力不怎么样&#xff0c;但是在设置障碍&#xff0c;折腾自己人的方面的创造性却登峰造极&#xff0c;比如网站备案。要备案也没什么问题&#xff0c;毕竟大家都是老老实实…

TDengine和DolphinDB哪个更好,哈哈哈哈,闲来无聊分析了一下。

#拥抱开源—涛思数据TDengine有奖征稿# TDengine是专为时序数据设计的&#xff0c;针对的是物联网、工业互联网、IT运维场景。这些场景是不需要特殊的查询函数的&#xff0c;更关心的是写入速度、查询速度。而且这些场景下&#xff0c;也需要一些其他数据库不具备的功能&#…

记一次 .NET 某WMS仓储打单系统 内存暴涨分析

一&#xff1a;背景 1. 讲故事七月中旬有一位朋友加wx求助&#xff0c;他的程序在生产上跑着跑着内存就飙起来了&#xff0c;貌似没有回头的趋势&#xff0c;询问如何解决&#xff0c;截图如下&#xff1a;和这位朋友聊下来&#xff0c;感觉像是自己在小县城当了个小老板&#…

一分钟读懂一个数学时代,看完不跪算我输!

▲ 点击查看上帝说&#xff0c;要有光&#xff0c;于是便有了光。而香农说&#xff0c;要有熵&#xff0c;于是信息化时代正式拉开帷幕。克劳德艾尔伍德香农&#xff08;Claude Elwood Shannon&#xff09;被尊称为“信息论之父”。不管你是否知道他&#xff0c;是如何看待他…

秋招面试我去了拼多多,直接被问JVMGC底层原理和算法,我吊打面试官

JVM 常用参数设置积累 # 堆的初始值&#xff0c;默认物理内存的1/64 -Xms: # 堆的最大值&#xff0c;默认物理内存的1/4 -Xmx: # 年轻代大小「在整个堆内存大小确定的情况下&#xff0c;增大年轻代将会减小年老代&#xff0c;反之亦然。此值关系到JVM垃圾回收&#xff0c;对系…

php中使用exec,system等函数调用系统命令

2019独角兽企业重金招聘Python工程师标准>>> 注意:要想使用这二个函数php.ini中的安全模式必须关闭&#xff0c;要不然为了安全起见php是不让调用系统命令的。  先看一下php手册对这二个函数的解释:  exec --- 执行外部程式  语法 : string exec ( string com…

了解jQuery技巧来提高你的代码

jQuery之所以如此流行并被从大公司到个人博客的几乎每个人都广泛使用&#xff0c;是因为它上手和使用相当简单&#xff0c;而且为我们提供了一些人都不知道的相当棒的特性。我认为jQuery的大多数用户更趋向于使用jQuery插件来解决面临的难题&#xff0c;这通常是明智的选择。但…

如何主动清空.NET数据库连接池?

一般我们的项目中会使用1到2个数据库连接配置&#xff0c;同程艺龙的数据库连接配置被收拢到统一的配置中心&#xff0c;由DBA统一维护&#xff0c;业务方通过某个配置字符串拿到的是开箱即用的Connection对象。DBA能在对业务方无侵入的情况下&#xff0c;给业务方切换备份数据…

假如有人在今天炸了支付宝的存储服务器...

全世界只有3.14 % 的人关注了青少年数学之旅今天在知乎看到了一个问题《假如有人把支付宝存储服务器炸了&#xff08;物理炸&#xff09;&#xff0c;大众在支付宝里的钱是不是就都没有了呢&#xff1f;》外行人问题。网站都是有服务器的&#xff0c;服务器都是有实体的。那么支…

Cookie全解

1. Cookie 可以存储哪些值 在 Cookie 中只能存储个人可识别信息. 个人可识别信息是指可以用来识别或联系用户的信息. 例如用户的姓名, 电子邮件, 家庭住址等. 必须强调的是, 这些可识别信息必须是非机密或重要信息. 2. 使用 Cookie 对象保存和读取客户端信息. 要存储一个 Cooki…

代码格式

2019独角兽企业重金招聘Python工程师标准>>> 1.参考&#xff1a;JavaScript程序编码规范 转载于:https://my.oschina.net/u/1791074/blog/283578