注意
此版本不是本文的最新版本。 对于当前版本,请参阅本文的 .NET 9 版本。
本文是 Blazor 电影数据库应用教程的第八部分,教您生成具有管理电影数据库功能的 ASP.NET Core Blazor Web App 的基础知识。
到本教程的这一部分为止,整个应用已经启用了交互性,但应用只在其 Counter
示例组件中采用了交互性。 本系列教程的这一部分将介绍如何在电影 Index
组件中采用交互性。
重要
确认应用未在运行,以便执行下一步操作。
采用交互性
交互性是指组件能够通过 C# 代码处理 UI 事件,例如单击按钮。 这些事件要么在服务器上由 ASP.NET Core 运行时处理,要么在客户端的浏览器中由基于 WebAssembly 的 Blazor 运行时处理。 本教程采用交互式服务器端呈现(交互式 SSR),一般也称为交互式服务器 (InteractiveServer
) 呈现。 客户端呈现 (CSR) 本身就是交互式的,在 Blazor 参考文档中有所介绍。
交互式 SSR 可实现丰富的用户体验,就像期待客户端应用提供的那样,但无需创建 API 终结点即可访问服务器资源。 UI 交互由服务器通过与浏览器的实时 SignalR 连接来处理。 交互式页面的页面内容是预呈现的,其中服务器上的内容最初生成并发送到客户端,而无需为呈现的控件启用事件处理程序。 通过预呈现,服务器在响应初始请求时会尽快输出页面的 HTML UI,从而使应用程序给用户的感觉更加灵敏。
查看 Program
文件 (Program.cs
) 中启用交互式 SSR 的 API。 Razor 组件服务被添加到应用中,使 Razor 组件能够从服务器静态呈现 (AddRazorComponents) 并通过交互式 SSR 执行代码 (AddInteractiveServerComponents):
builder.Services.AddRazorComponents()
.AddInteractiveServerComponents();
MapRazorComponents 将根 App
组件中定义的组件映射到给定的 .NET 程序集,并呈现可路由组件,而 AddInteractiveServerRenderMode 会配置应用的 SignalR 中心以支持交互式 SSR:
app.MapRazorComponents<App>()
.AddInteractiveServerRenderMode();
在本教程系列的这部分内容中,电影页面不需要调用 AddInteractiveServerComponents 和 AddInteractiveServerRenderMode,因为应用只为电影组件采用了静态 SSR 功能。 本文将介绍如何在电影 Index
组件中采用交互功能。
当 Blazor 设置组件的呈现类型时,该呈现被称为组件的呈现模式。 下表列出了在 Blazor Web App 中呈现 Razor 组件的可用呈现模式。
名称 | 说明 | 呈现位置 | 交互 |
---|---|---|---|
静态服务器 | 静态服务器端呈现(静态 SSR) | 服务器 | 否 |
交互式服务器 | 使用 Blazor Server 的交互式服务器端呈现(交互式 SSR)。 | 服务器 | 是 |
交互式 WebAssembly | 使用 Blazor WebAssembly 的客户端呈现 (CSR)。 | 客户端 | 是 |
交互式自动 | 下载 Blazor 捆绑包后,在后续访问时先使用 Blazor Server 然后使用 CSR 的交互式 SSR。 | 服务器,然后客户端 | 是 |
要对组件应用呈现模式,开发人员可以在组件实例或组件定义中使用 @rendermode
指令或指令属性:
下面的示例展示了如何使用
@rendermode
指令属性在组件实例上设置呈现模式。 下面的示例使用了父级聊天 (Chat
) 组件中的假设对话框 (Dialog
) 组件。在
Components/Pages/Chat.razor
文件中:<Dialog @rendermode="InteractiveServer" />
下面的示例展示了如何使用
@rendermode
指令在组件定义上设置呈现模式。 下面的示例显示了在假设的销售预测 (SalesForecast
) 组件定义文件 (.razor
) 中设置呈现模式。在
Components/Pages/SalesForecast.razor
文件顶部:@page "/sales-forecast" @rendermode InteractiveServer
使用上述方法,可以按页面/组件应用呈现模式。 但是,整个应用可以通过一个根组件来采用单一的呈现模式,然后通过继承设置加载的其他每个组件的呈现模式。 这被称为全局交互性,而不是每个页面/组件的交互性。 如果大部分应用都需要交互功能,那么全局交互性就非常有用。 全局交互性通常通过 App
组件应用,该组件是根据 Blazor Web App 项目模板创建的应用的根组件。
注意
有关呈现模式和全局交互性的详细信息,请参阅 Blazor 的参考文档。 在本教程中,应用仅在每个页面/组件的基础上采用交互式 SSR。 教程结束后,可以使用此应用自行学习其他组件的呈现模式和全局交互位置。
打开电影 Index
组件文件 (Components/Pages/MoviePages/Index.razor
),在 @page
指令后紧接着添加以下 @rendermode
指令,使组件具有交互性:
@rendermode InteractiveServer
为了了解组件的交互性如何增强用户体验,让我们在下面的章节中为应用提供三个增强功能:
- 向电影
QuickGrid
组件添加分页。 - 使
QuickGrid
组件可排序。 - 用 C# 代码替换按标题筛选电影的 HTML 表单,这些 C# 代码:
- 在服务器上运行。
- 通过基础 SignalR 连接交互式呈现内容。
为 QuickGrid 添加分页
QuickGrid
组件可以从数据库中对数据进行分页。
打开 Index
组件 (Components/Pages/Movies/Index.razor
)。 在 @code
块中添加 PaginationState 实例。 由于本教程只使用五个电影记录来进行演示,因此请将 ItemsPerPage 设置为 2
项,以便演示分页。 通常,要显示的项目数量会设置为一个较大的值,或通过下拉列表来动态设置。
private PaginationState pagination = new PaginationState { ItemsPerPage = 2 };
将 QuickGrid
组件的 Pagination 属性设置为 pagination
:
- <QuickGrid Class="table" Items="FilteredMovies">
+ <QuickGrid Class="table" Items="FilteredMovies" Pagination="pagination">
要在 QuickGrid
组件下方提供分页 UI,请在 QuickGrid
组件下方添加 Paginator
组件。 将 Paginator.State 设置为 pagination
:
<Paginator State="pagination" />
运行应用并导航至电影 Index
页。 可以按每页两个电影的速度对电影项目进行分页:
组件为交互式。 页面不重新加载就无法进行分页。 分页是通过浏览器和服务器之间的 SignalR 连接实时执行的,分页操作在服务器上进行,并将呈现结果发回客户端供浏览器显示。
将 ItemsPerPage 更改为更合理的值,例如每页五个项目:
- private PaginationState pagination = new PaginationState { ItemsPerPage = 2 };
+ private PaginationState pagination = new PaginationState { ItemsPerPage = 5 };
可排序 QuickGrid
打开 Index
组件 (Components/Pages/Movies/Index.razor
)。
将 Sortable="true"
(Sortable) 添加到标题 PropertyColumn<TGridItem,TProp>:
- <PropertyColumn Property="movie => movie.Title" />
+ <PropertyColumn Property="movie => movie.Title" Sortable="true" />
可以通过选择 Title 列,按电影标题对 QuickGrid 进行排序。 页面不重新加载就无法进行排序。 排序通过 SignalR 连接实时执行,排序操作在服务器上进行,并将呈现的结果发送回客户端:
使用 C# 代码和交互性按标题进行搜索
在本系列教程的前一部分,我们修改了 Index
组件,让用户可以按标题来筛选电影。 这通过以下方式来实现:
- 添加一个 HTML 表单,向服务器发送 GET 请求,并将用户的标题搜索字符串作为查询字符串的字段-值对(例如,如果用户搜索“
road warrior
”,则为?titleFilter=road+warrior
)。 - 在组件中添加代码,从查询字符串中获取标题搜索字符串,并用它来筛选数据库记录。
上述方法对采用静态 SSR 的组件很有效,在这种组件中,客户端和服务器之间的唯一交互是通过 HTTP 请求进行的。 客户端和服务器之间没有实时 SignalR 连接,服务器上的应用无法根据用户在组件 UI 中的操作以交互方式处理 C# 代码并返回内容。
既然该组件是交互式的,那么它就可以通过用于绑定和事件处理的 Blazor 功能提供更好的用户体验。
添加一个委托事件处理程序,用户可以触发它来筛选数据库中的电影记录。 该方法使用 TitleFilter
属性的值来执行操作。 如果用户清除 TitleFilter
并进行搜索,则该方法将加载整个电影列表以供显示。
删除 @code
块中的以下行:
- [SupplyParameterFromQuery]
- private string? TitleFilter { get; set; }
- private IQueryable<Movie> FilteredMovies =>
- context.Movie.Where(m => m.Title!.Contains(TitleFilter ?? string.Empty));
用以下代码替换已删除的代码:
private string titleFilter = string.Empty;
private IQueryable<Movie> FilteredMovies =>
context.Movie.Where(m => m.Title!.Contains(titleFilter));
接下来,组件应将 titleFilter
字段绑定到 <input>
元素,这样用户输入就会存储在 titleFilter
变量中。 在 Blazor 中通过 @bind
指令属性来实现绑定。
从组件中移除 HTML 表单:
- <form action="/movies" data-enhance>
- <input type="search" name="titleFilter" />
- <input type="submit" value="Search" />
- </form>
在其位置添加以下 Razor 标记:
<input type="search" @bind="titleFilter" @bind:event="oninput" />
@bind:event="oninput"
会为 HTML 的 oninput
事件执行绑定,当用户在搜索框中键入直接导致 <input>
元素的值发生变化时就会触发该事件。 将 QuickGrid 与 FilteredMovies
绑定。 当 titleFilter
随搜索框的值变化时,重新呈现绑定到 FilteredMovies
方法的 QuickGrid 会根据 titleFilter
的更新值来筛选电影实体。
运行该应用,在搜索栏中输入“road warrior
”,注意每输入一个字符,QuickGrid 就会被筛选一次,直到搜索栏中输入“road
”(“road”后跟一个空格)时,就会剩下 The Road Warrior 这部电影。
筛选数据库记录的工作在服务器上进行,服务器通过同一 SignalR 连接交互式地发送 HTML 返回显示。 页面不会重新加载。 用户感觉自己与页面的交互就像是在客户端上运行代码。 实际上,代码正在运行服务器。
在这种情况下提交 GET 请求,也可以使用 JavaScript 向服务器提交请求,而不是 HTML 表单 — 既可使用 Fetch API,也可使用 XMLHttpRequest API。 在大多数情况下,可以在交互式组件中使用 Blazor 和 C# 来替换 JavaScript。
为 QuickGrid
组件设定样式
可以将样式应用于呈现的 QuickGrid
组件,使用 CSS 隔离将样式表隔离到 Index
组件。
通过使用文件名格式 {COMPONENT NAME}.razor.css
添加样式表文件来应用 CSS 隔离,其中 {COMPONENT NAME}
占位符是组件名称。
若要将样式应用于子组件(如 QuickGrid
组件的 Index
组件),请使用 ::deep
伪元素。
在 MoviePages
文件夹中,为 Index
组件添加以下样式表。 使用 ::deep
伪元素使行高 3em
,并使表单元格内容垂直居中。
Components/Pages/MoviePages/Index.razor.css
:
::deep tr {
height: 3em;
}
::deep tr > td {
vertical-align: middle;
}
::deep
伪元素仅适用于子代元素,因此 QuickGrid
组件必须用 <div>
或其他一些块级元素包装,才能向其应用样式。
在 Components/Pages/MoviePages/Index.razor
中,将 <div>
标记放在 QuickGrid
组件周围:
+ <div>
<QuickGrid ...>
...
</QuickGrid>
+ </div>
Blazor 重写 CSS 选择器以匹配组件呈现的标记。 重写的 CSS 样式捆绑并生成为静态资产,因此无需采取进一步操作即可将样式应用于呈现的 QuickGrid
组件。
清理
完成教程并从本地系统中删除示例应用后,还可以在 Visual Studio 的 SQL Server 对象资源管理器 (SSOX) 中删除 BlazorWebAppMovies
数据库:
- 从菜单栏中选择查看>SQL Server 对象资源管理器以访问 SSOX。
- 选择
SQL Server
>(localdb)\MSSQLLocalDB
>Databases
旁边的三角形,以便显示数据库列表。 - 右键单击列表中的
BlazorWebAppMovies
数据库,然后选择“删除”。 - 在选择“确定”之前,选中复选框以关闭现有集合。
在 SSOX 中删除数据库时,数据库的物理文件将从 Windows 用户文件夹中删除。
完成教程并从本地系统中删除示例应用后,还可以手动删除 BlazorWebAppMovies
数据库。 数据库的位置因平台和操作系统而异,但可以通过应用设置文件 (appsettings.json
) 的数据库连接字符串中指示的文件名进行搜索。
完成教程并从本地系统中删除示例应用后,还可以手动删除 BlazorWebAppMovies
数据库。 数据库的位置因平台和操作系统而异,但可以通过应用设置文件 (appsettings.json
) 的数据库连接字符串中指示的文件名进行搜索。
祝贺你!
恭喜你完成教程系列! 希望你喜欢这个 Blazor 教程。 Blazor 提供的功能远远超出了本系列所能涵盖的范围,诚邀你浏览 Blazor 文档、示例和示例应用,了解更多信息。 祝你使用 Blazor 编码愉快!
后续步骤
如果你是 Blazor 新手,建议阅读以下 Blazor 文章,它们介绍了 Blazor 开发的重要一般信息:
- ASP.NET Core Blazor
- ASP.NET Core Blazor 支持的平台
- 用于 ASP.NET Core 的工具Blazor
- ASP.NET Core Blazor 托管模型
- ASP.NET Core Blazor 项目结构
- ASP.NET Core Blazor 基础知识和其他基础知识节点文章。
- ASP.NET Core Razor 组件和其他组件节点文章。
- ASP.NET Core Blazor 窗体概述
- ASP.NET Core Blazor JavaScript 互操作性(JS 互操作)和其他 JavaScript 互操作文章。
- ASP.NET Core Blazor 身份验证和授权
- 托管和部署 ASP.NET Core Blazor
- 带 Entity Framework Core (EF Core) 的 ASP.NET Core Blazor 涵盖 Blazor 应用中 EF Core 的并发性。
有关将缩略图文件上传功能添加到本教程的示例应用的指南,请参阅 ASP.NET Core Blazor 文件上传。
在文档网站的侧栏导航中,文章按主题进行组织,并大致按照从一般到特殊或从基本到复杂的顺序排列。 开始学习 Blazor 时,最好的方法是自上而下地阅读目录。
使用已完成的示例来排除故障
如果在学习本教程时遇到无法从文本中解决的问题,请将代码与 Blazor 示例存储库中已完成的项目进行对比:
Blazor 示例 GitHub 存储库 (dotnet/blazor-samples
)
选择最新版本文件夹 本教程项目的示例文件夹被命名为 BlazorWebAppMovies
。