Appearance
使用 Blazor 构建 Web 应用
了解 Blazor
Blazor 是开发人员可以通过编写 C# 代码来创建丰富的交互式用户界面(UI)的框架。 使用 Blazor,可以为所有代码(服务器端和客户端)使用相同的语言。 可以渲染它以在多种不同的浏览器中显示,包括移动设备上的浏览器。
TIP
Blazor 应用中的代码有两个托管模型:
Blazor 服务器:在此模型中,应用在 ASP.NET Core 应用中的 Web 服务器上执行。 在客户端上,UI 更新、事件和 JavaScript 调用通过客户端和服务器之间的 SignalR 连接发送。 在本模块中,我们将讨论此模型并编写代码。
Blazor WebAssembly:在此模型中,下载 Blazor 应用及其依赖项,并在浏览器中运行 .NET 运行时。
在 Blazor 中,UI 是从称为组件的自包含代码部分构建的。 每个组件可以包含 HTML 和 C# 代码的组合。 组件是使用 Razor 语法编写的,其中代码使用 @code
指令进行标记。 其他指令可用于访问变量、绑定到值并实现其他呈现任务。 编译应用后,HTML 和代码将编译为组件类。 组件被写入具有 .razor
扩展名的文件中。
TIP
Razor 语法用于将 .NET 代码嵌入网页。 可以在 ASP.NET MVC(模型-视图-控制器)应用程序中使用它,其中的文件具有 .cshtml
扩展名。 Blazor 中使用 Razor 语法编写组件。 这些组件反而具有 .razor
扩展,控制器和视图之间没有严格的分隔。
使用 Blazor 构建你的第一个 Web 应用
创建并运行 Blazor Web 应用
使用 .NET CLI 创建新的 Blazor 应用
sh
$ dotnet new blazor -o BlazorApp
已成功创建模板“Blazor Web 应用”。
此模板包含除 Microsoft 以外其他方的技术,请参阅 https://aka.ms/aspnetcore/9.0-third-party-notices 以获取详细信息。
正在处理创建后操作...
正在还原 D:\dotnet-training\BlazorApp\BlazorApp.csproj:
已成功还原。
默认组件包括 Index.razor 主页和 Counter.razor 演示组件。 这两个组件都放置在 Pages 文件夹中。 可以修改这些视图以满足你的需求,或将其删除,并将其替换为新组件。
Blazor 项目结构
生成的项目都包含以下文件和页面:
Program.cs
是启动服务器和配置应用服务和中间件的应用的入口点。App.razor
是应用的根组件。Routes.razor
配置 Blazor 路由器。- Components/Pages 目录包含应用的一些示例网页。
BlazorApp.csproj
定义应用项目及其依赖项,可以通过双击解决方案资源管理器中的项目节点来查看。- Properties 目录中的
launchSettings.json
文件为本地开发环境定义不同的配置文件设置。 在创建项目时自动分配端口号,并将其保存在此文件上。
使用 .NET CLI 运行应用
sh
$ dotnet watch
dotnet watch 🔥 Hot reload enabled. For a list of supported edits, see https://aka.ms/dotnet/hot-reload.
💡 Press "Ctrl + R" to restart.
dotnet watch ⌚ Building D:\dotnet-training\BlazorApp\BlazorApp.csproj ...
dotnet watch 🔨 Build succeeded: D:\dotnet-training\BlazorApp\BlazorApp.csproj
从 D:\dotnet-training\BlazorApp\Properties\launchSettings.json 使用启动设置...
info: Microsoft.Hosting.Lifetime[14]
Now listening on: http://localhost:5104
info: Microsoft.Hosting.Lifetime[0]
Application started. Press Ctrl+C to shut down.
info: Microsoft.Hosting.Lifetime[0]
Hosting environment: Development
info: Microsoft.Hosting.Lifetime[0]
Content root path: D:\dotnet-training\BlazorApp
warn: Microsoft.AspNetCore.HttpsPolicy.HttpsRedirectionMiddleware[3]
Failed to determine the https port for redirect.
已成功运行第一个 Blazor 应用!
Razor 组件
设置开发环境后,让我们探索 Blazor 项目的结构,并了解 Blazor 组件的工作原理。
应用的主页由位于 Components/Pages 目录中的 Home.razor 文件定义。 Home.razor 包含以下代码:
razor
@page "/"
<PageTitle>Home</PageTitle>
<h1>Hello, world!</h1>
Welcome to your new app.
@page
指令指定了此页面的路径,因此当用户导航到应用的根目录时,Home 组件将被显示。 该 PageTitle
标记是一个 Blazor 组件,用于设置当前页的标题,使其显示在浏览器选项卡中。文件的其余部分是定义页面内容的普通 HTML。
什么是 Razor?
Razor 是基于 HTML 和 C# 的标记语法。 Razor 文件 (.razor) 包含纯 HTML,然后包含 C# 来定义任何呈现逻辑,例如条件、控制流和表达式计算。 然后,Razor 文件编译为封装组件呈现逻辑的 C# 类。
什么是 Razor 组件?
如果浏览 Blazor 项目中的文件,你会注意到构成项目的大多数文件都是 .razor 文件。 在 Blazor 中,Razor 文件定义构成应用 UI 部分的可重用组件。 组件定义要呈现的 HTML 以及如何处理用户事件。
在编译时,每个 Razor 组件都内置在 C# 类中。 该类可以包含常见的 UI 元素,例如状态、呈现逻辑、生命周期方法和事件处理程序。 由于在 Razor 中创建的 Blazor 组件只是 C# 类,因此可以使用组件的任意 .NET 代码。
- 使用组件
若要使用另一个组件中的组件,请添加一个 HTML 样式标记,其名称与组件名称匹配。 例如,如果你有一个名为 MyButton.razor 的组件,你可以通过添加 <MyButton />
标签将 MyButton 组件添加到另一个组件。
- 组件参数
组件还可以具有参数,允许在使用组件时将数据传递到组件。 组件参数通过向具有 [Parameter]
属性的组件添加公共 C# 属性来定义。 然后,可以使用与属性名称匹配的 HTML 样式属性为组件参数指定值。 参数的值可以是任何 C# 表达式。
@code
块
Razor 文件中的 @code
块用于将 C# 类成员(字段、属性和方法)添加到组件。 可以使用 @code
来跟踪组件状态,添加组件参数,实现组件生命周期事件,并定义事件处理程序。
尝试使用 Counter 组件
在正在运行的应用中,选择左侧边栏中的“Counter”选项卡导航到计数器页面。 随后应会显示以下页面:
(图片来源:自己截的)
选择“Click me”按钮,在不刷新页面的情况下递增计数。 在网页中递增计数器通常需要编写 JavaScript,但使用 Blazor 时,可以使用 C#。
可在 Components/Pages/Counter.razor 处找到 Counter 组件的实现。
浏览器中针对 /counter
的请求(由顶部的 @page
指令指定)会导致 Counter 组件呈现其内容。 该 @rendermode
指令为组件启用交互式服务器呈现,以便它可以处理来自浏览器的用户界面事件。
每次选择“单击我”按钮时会出现以下情况:
onclick
事件被触发。 调用 IncrementCount
方法。 currentCount
递增。 组件被渲染以显示更新后的计数。
添加组件
向主页添加 Counter 组件
打开 Components/Pages/Home.razor 文件。
通过在 Home.razor 文件的末尾添加
<Counter />
元素,向页面添加 Counter 组件。
razor
@page "/"
<PageTitle>Home</PageTitle>
<h1>Hello, world!</h1>
Welcome to your new app.
<Counter />
- 通过重启应用或使用热重载来应用更改。 组件 Counter 显示在主页上。
(图片来源:自己截的)
修改组件
修改主页的 Counter 组件
定义组件上的 Counter 参数,以指定每次单击按钮时递增多少。
为
IncrementAmount
添加具有 [Parameter] 特性的公共属性。将
IncrementCount
方法更改为在递增IncrementAmount
的值时使用currentCount
的值。
Counter.razor 中更新的代码应如下所示:
razor
@page "/counter"
@rendermode InteractiveServer
<PageTitle>Counter</PageTitle>
<h1>Counter</h1>
<p role="status">Current count: @currentCount</p>
<button class="btn btn-primary" @onclick="IncrementCount">Click me</button>
@code {
[Parameter]
public int IncrementAmount { get; set; } = 1;
private int currentCount = 0;
private void IncrementCount()
{
currentCount += IncrementAmount;
}
}
- 在 Home.razor 中,更新 元素来添加一个
IncrementAmount
属性,它会将增量更改为 10,如以下代码中的最后一行所示:
razor
@page "/"
<PageTitle>Home</PageTitle>
<h1>Hello, world!</h1>
Welcome to your new app.
<Counter IncrementAmount="10" />
将更改应用到正在运行的应用。
Home 组件现在有自己的计数器,每次选择“Click me”按钮时,计数器值都递增 10,如下图所示。
(图片来源:自己截的)
而 /counter
的 Counter 组件继续增加 1。
使用 Blazor 构建待办事项列表
Razor 指令
Razor 指令是 Razor 语法中的保留关键字,会影响 Razor 文件的编译方式。 Razor 指令始终以 @
字符开头。 某些 Razor 指令出现在新行的开头,例如 @page
和 @code
,而其他指令则是可以作为属性应用于元素的属性,例如 @bind
。 可以在 Razor 语法参考中找到 Razor 指令的完整列表。
数据绑定和事件
呈现 C# 表达式值
若要在 Razor 中呈现 C# 表达式的值,可以使用前导 @
字符。 例如,Counter 组件可以呈现其 currentCount
字段的值,如下所示:
razor
<p role="status">Current count: @currentCount</p>
Razor 通常可以判断出 C# 表达式何时结束,以及你何时转换回编写 HTML。 但是,也可以使用圆括号()
来明确表达式的开始和结束。
razor
<p role="status">Current count: @(currentCount)</p>
添加控制结构
可以使用 C# if 语句有条件地呈现某些内容,如下所示:
razor
@if (currentCount > 3)
{
<p>You win!</p>
}
还可以使用 C# 循环访问数据并呈现项列表:
razor
<ul>
@foreach (var item in items)
{
<li>@item.Name</li>
}
</ul>
处理事件
Blazor 组件通常处理 UI 事件。 若要从 UI 元素为事件指定事件回调,可以使用以 @on
开头且以事件名称结尾的属性。 例如,可以使用 IncrementCount
属性将 @onclick
方法指定为按钮单击事件的处理程序,如下所示:
razor
<ul>
@foreach (var item in items)
{
<li>@item.Name</li>
}
</ul>
还可以为其他 HTML 事件指定 C# 事件处理程序,例如 @onchange
、@oninput
等。 事件处理方法可以是同步的,也可以是异步的。 还可以使用 C# Lambda 表达式内联定义事件处理程序:
razor
<button class="btn btn-primary" @onclick="() => currentCount++">Click me</button>
事件处理程序方法可以选择采用包含事件相关信息的事件参数。 例如,你可以访问已更改的输入元素的值,如下所示:
razor
<input @onchange="InputChanged" />
<p>@message</p>
@code {
string message = "";
void InputChanged(ChangeEventArgs e)
{
message = (string)e.Value;
}
}
运行事件处理程序后,Blazor 将自动呈现具有新状态的组件,以便在输入更改后会显示该消息。
数据绑定
通常,需要将 UI 元素的值绑定到代码中的特定值。 当 UI 元素的值更改时,代码值应更改,当代码值更改时,UI 元素应显示新值。 Blazor 的数据绑定支持可以轻松设置这种双向数据绑定。
可以使用 @bind
属性将 UI 元素绑定到代码中的特定值。 例如:
razor
<input @bind="text" />
<button @onclick="() => text = string.Empty">Clear</button>
<p>@text</p>
@code {
string text = "";
}
更改输入的值时,text
字段将更新为新值。 单击“清除”按钮更改 text
字段的值时,输入的值也会被清除。
启用交互性
若要处理来自组件的 UI 事件并使用数据绑定,该组件必须是交互式的。 默认情况下,Blazor 组件从服务器静态呈现,这意味着它们生成 HTML 以响应请求,否则无法处理 UI 事件。 可以通过使用 @rendermode
指令应用交互式呈现模式,使组件具有交互性。
可以将 @rendermode
指令应用于组件定义:
razor
@rendermode InteractiveServer
或组件实例:
razor
<Counter @rendermode="InteractiveServer" />
Counter 组件是目前应用中唯一的交互式组件,它使用交互式服务器呈现。 交互式服务器呈现通过与浏览器的 WebSocket 连接处理来自服务器的 UI 事件。 Blazor 通过此连接将 UI 事件发送到服务器,以便应用的组件可以处理它们。 然后,Blazor 会使用呈现的更新来更新浏览器 DOM。
或者,Blazor 组件可以使用 InteractiveWebAssembly
呈现模式以交互方式从客户端呈现。 在此模式下,组件代码将下载到浏览器并使用基于 WebAssembly 的 .NET 运行时运行客户端。
选择使用哪种交互式呈现模式取决于应用的要求。 目前,Blazor 项目仅针对基于服务器的呈现进行设置,因此在本模块中,我们继续使用静态和交互式服务器呈现。
创建待办事项列表
创建新的 Blazor Web 应用项目。
将 Todo.razor 文件添加到 Components/Pages 文件夹
在 Visual Studio 和 Visual Studio Code 中,可以通过右键单击解决方案资源管理器中的 Components/Pages 文件夹并选择添加新文件的相应选项来添加 Razor 文件。
还可以使用 .NET CLI 通过以下命令创建 Razor 文件:
sh
$ dotnet new razorcomponent -n Todo -o Components/Pages
上述命令中的 -n|--name 指定了新的 Razor 组件的名称。 新组件是在项目具有 Components/Pages 选项的 -o|--output 文件夹中创建的。
- 打开 Todo 组件,生成的模板内容如下:
razor
<h3>Todo</h3>
@code {
}
在文件的顶部添加 @page
Razor 指令(其相对 URL 为 /todo
),并将呈现模式设置为 InteractiveServer
,以便组件可以处理 UI 事件。
razor
@page "/todo"
@rendermode InteractiveServer
<h3>Todo</h3>
@code {
}
- 将更改应用到应用程序,并尝试浏览到“/todo”以查看新页面。
将待办事项页面添加到导航菜单
新的待办事项列表页面尚未与其他现有页面一起出现在导航菜单中。 导航菜单在 NavMenu
组件中定义,该组件是应用程序布局的一部分。 更新 NavMenu
组件,以添加指向待办事项列表页的链接。
打开 Components/Layout/NavMenu.razor。
查找
nav
组件中的NavMenu
元素,并在天气页的现有导航项下方添加以下div
元素。
razor
<div class="nav-item px-3">
<NavLink class="nav-link" href="todo">
<span class="bi bi-list-nested-nav-menu" aria-hidden="true"></span> Todo
</NavLink>
</div>
NavLink
组件是一个内置 Blazor 组件,用于呈现定位标记。 如果当前浏览器地址与 href
的 NavLink
匹配,它还会呈现一个可用于设置链接样式的 active
CSS 类。
应用此更改后,现在应会在导航菜单中显示待办事项页面。
(图片来源:自己截的)
生成待办事项列表
- 在项目的根目录中创建新的
TodoItem.cs
文件(与Program.cs
同级),并向其添加以下 C# 类。
cs
public class TodoItem
{
public string? Title { get; set; }
public bool IsDone { get; set; } = false;
}
- 在
Todo.razor
为@code
块中添加todos
字段。
razor
@code {
private List<TodoItem> todos = new();
}
- 使用
foreach
循环呈现所有todos
的未排序列表。
razor
<ul>
@foreach (var todo in todos)
{
<li>@todo.Title</li>
}
</ul>
你还不会看到为待办事项列表呈现的任何内容,因为该列表是空的。 你需要一种方法来添加一些待办事项。
添加待办事项
添加一些 UI 元素,以便向列表添加待办事项。
- 在
Todo.razor
中未排序的列表下方添加一个input
标签和button
标签。
razor
<input />
<button>Add todo</button>
- 创建
newTodo
字符串字段并使用@bind
指令属性将其添加到input
。
razor
<input @bind="newTodo" />
<button>Add todo</button>
@code {
private List<TodoItem> todos = new();
string newTodo = string.Empty;
}
- 将
@onclick
处理程序添加到button
,该处理程序根据TodoItem
的值将新的newTodo
添加到todos
列表,然后将newTodo
的值重置为空字符串。
razor
<input @bind="newTodo" />
<button @onclick="AddTodo">Add todo</button>
@code {
private List<TodoItem> todos = new();
string newTodo = string.Empty;
void AddTodo()
{
if (!string.IsNullOrWhiteSpace(newTodo))
{
todos.Add(new TodoItem { Title = newTodo });
newTodo = string.Empty;
}
}
}
- 检查现在是否可以添加待办事项并且它们是否显示在列表中。添加每个待办事项后
input
值也应重置。
添加复选框并计算未完成的待办事项
你需要一种方法将待办事项标记为已完成,编辑现有的待办事项以及计算尚未完成的待办事项数量。
- 更新
li
元素的内容以呈现绑定到input
的checkbox
类型的todo.IsDone
和绑定到input
的文本类型的todo.Title
。
razor
<ul>
@foreach (var todo in todos)
{
<li>
<input type="checkbox" @bind="@todo.IsDone" />
<input @bind="@todo.Title" />
</li>
}
</ul>
- 更新
<h3>
标头,显示尚未完成的待办项数目(IsDone
是false
)。
razor
<h3>Todo (@todos.Count(todo => !todo.IsDone))</h3>
- 添加完代码后,Todo.razor 文件应如下所示:
razor
@page "/todo"
@rendermode InteractiveServer
<h3>Todo (@todos.Count(todo => !todo.IsDone))</h3>
<ul>
@foreach (var todo in todos)
{
<li>
<input type="checkbox" @bind="@todo.IsDone" />
<input @bind="@todo.Title" />
</li>
}
</ul>
<input @bind="newTodo" />
<button @onclick="AddTodo">Add todo</button>
@code {
private List<TodoItem> todos = new();
string newTodo = string.Empty;
void AddTodo()
{
if (!string.IsNullOrWhiteSpace(newTodo))
{
todos.Add(new TodoItem { Title = newTodo });
newTodo = string.Empty;
}
}
}
- 将更改应用到应用程序后,请尝试添加项、编辑项以及标记已完成的待办事项以测试组件。
(图片来源:自己截的)
你的 Blazor 待办事项列表现已完成 ✅。