Blazor SPA 的本质是什么以及服务器端渲染如何与 Blazor 的新 Web 应用程序配合使用

Blazor 通常被称为单页应用程序 (SPA) 框架。当我第一次开始使用 Blazor 时,我对 SPA 的含义、组件如何为 SPA 架构做出贡献以及所有这些如何与交互性联系在一起感到困惑。

今天,我将解答大家可能关心的三个问题:

  1. 什么是 SPA?
  2. 了解所有新的“Blazor Web App”模板。
  3. 是什么使 Blazor 成为 SPA 应用程序?

什么是 SPA?

图 1 显示了传统的 Web 应用程序如何处理用户请求,它通常涉及用户为每个新页面向服务器发出请求。

例如,向服务器发送对“www.facebook.com/home.html”这样的主页的请求,服务器处理该请求然后返回主页。而当用户导航到个人资料页面时,将发出另一个对“www.facebook.com/profile.html”的请求,服务器现在将返回个人资料页面。

每次交互都会导致整个页面重新加载。


图 1:传统 Web 应用架构

现在让我们看看 SPA 应用程序是如何工作的,

用户体验保持不变。然而,在服务器上,我们不再提供完整的网页,而是使用组件。这是因为 Blazor 是一个基于组件的单页应用程序。

您可能想知道,哪个单页?在图 2 所示的架构中,App.razor是所有用户请求定向到的网页。服务器加载此单页并将其替换为请求的组件。

例如,当用户请求主页时,App.razor 会加载Home.razor组件。同样,当用户请求个人资料页面时,服务器首先加载App.razor,然后再加载 Profile.razor。

如下所示,Profile组件有附加组件, UserInfo.razor和UserOrders.razor。这称为组件层次结构。


图 2:基于 Blazor SPA 组件的架构

相比之下,SPA 会加载单个页面,并在用户与应用交互时动态更新内容。这是通过动态加载组件来实现的,无需完全重新加载,从而带来更流畅的用户体验。

例如,在 YouTube 上,当你给视频添加评论时,评论部分会更新,而不会中断视频播放。这是因为评论部分是一个单独的组件,可以独立刷新,而不会影响其他部分。

创建 Blazor Web 应用

让我们通过创建 Blazor Web 应用程序来看一下它的实际效果。

  • 打开 Visual Studio 并选择 Blazor Web App 模板。


图 3:创建新的 Blazor Web 应用程序

  • 为您的应用命名并选择一个位置。


图 4:Blazor 中的项目配置

  • 选择“.NET 8” 作为框架。将“身份验证类型”设置为“无” ,并为“交互式渲染模式”选择“无”,以确保我们使用 Blazor SSR(静态服务器端渲染)。忽略“交互位置选项”,因为当为交互式渲染模式选择“无” 时,它不适用。最后,点击创建按钮。


图 5:Blazor Web 应用的附加信息

在解决方案资源管理器中,您将看到类似以下的结构:


图 6:Blazor Web 应用文件夹结构

理解代码

首先,让我向您展示您请求的页面在 Blazor 应用中加载的顺序。请注意数字,因为它们代表控制流。我们将在下面详细介绍每个文件,解释它们在此过程中的作用。


图 7:Blazor Web 应用中的控制流

让我们回顾一下早期的 C# 时代。众所周知,Program.cs是 C# 应用程序的入口点,对于 Blazor 来说,它遵循同样的原则

以下是 Program.cs 中的代码

using MyFirstBlazorWebApp.Components;var builder = WebApplication.CreateBuilder(args);// Add services to the container.
builder.Services.AddRazorComponents();var app = builder.Build();// Configure the HTTP request pipeline.
if (!app.Environment.IsDevelopment())
{app.UseExceptionHandler("/Error", createScopeForErrors: true);// The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.app.UseHsts();
}app.UseHttpsRedirection();app.UseStaticFiles();
app.UseAntiforgery();app.MapRazorComponents<App>();app.Run();

代码片段 1:Program.cs

该文件处理用户发出的 HTTP 请求(例如,/index、/profile),如上面的架构图所示。

从第 18行到第 21行,你可以看到专门用于管理这些 HTTP 请求的方法。在第 23行,HTTP 请求被映射到名为App 的组件。

你可能会问,这是什么应用程序?

这与我们架构图(图 2)中显示的App.razor相同,这意味着所有请求在到达App.razor之前都会流经Program.cs。

让我们探索一下 App.razor 中的内容

<!DOCTYPE html>
<html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1.0" /><base href="/" /><link rel="stylesheet" href="bootstrap/bootstrap.min.css" /><link rel="stylesheet" href="app.css" /><link rel="stylesheet" href="MyFirstBlazorWebApp.styles.css" /><link rel="icon" type="image/png" href="favicon.png" /><HeadOutlet />
</head><body><Routes /><script src="_framework/blazor.web.js"></script>
</body></html>

代码片段 2:App.razor

这主要是标准 HTML,但有一个明显的区别:在第 16行,它调用名为的组件。

组件的作用是定位并加载特定的请求组件。例如,当用户请求主页时,它会找到Home.razor,而当用户请求个人资料页面时,它会找到Profile.razor并替换它。

那么 组件包含什么?

<Router AppAssembly="typeof(Program).Assembly"><Found Context="routeData"><RouteView RouteData="routeData" DefaultLayout="typeof(Layout.MainLayout)" /><FocusOnNavigate RouteData="routeData" Selector="h1" /></Found>
</Router>

代码片段 3:Routes.razor

Router组件负责定位请求的组件并将其应用到第 3 行的MainLayout。路由完成后,Router 组件会更新MainLayout。

让我们打开 MainLayout.razor

@inherits LayoutComponentBase<div class="page"><div class="sidebar"><NavMenu /></div><main><div class="top-row px-4"><a href="https://learn.microsoft.com/aspnet/core/" target="_blank">About</a></div><article class="content px-4">@Body</article></main>
</div>

代码片段 4:MainLayout.razor

注意第 14行,其中有一个“@Body” 占位符。这是插入请求组件的位置。因此,当 请求“Home.razor”时,其 HTML 内容将替换“@Body” 占位符,整个页面将通过路由器发送回浏览器中显示。

提示:其余代码代表您的 Web 应用的布局。如果您想为您的应用定义一个带有侧边栏、页眉、页脚和动态中心内容的自定义布局,这里就是您要做的。

不要太担心这些理论;让我们继续运行该应用程序,看看它的实际作用。


图 8:加载 Blazor 应用程序

在这里,您可以看到左侧的侧边栏(来自MainLayout.razor的第 4 个代码片段)和中间加载的主体内容。当 Web 应用首次运行时,它会重定向到根 URL (/) 。在我们的演示应用中,这由Home.razor表示,如图 7 中的项目 5 所示。

它看起来是这样的:

@page "/"<PageTitle>Home</PageTitle><h1>Hello, world!</h1>Welcome to your new app.

代码片段 5:Home.razor

现在,让我们更改用户请求并点击侧边栏中的天气按钮。您会注意到 URL 更改为"https://localhost:7106/weather"。

此时,App.razor将要求Router查找具有“@page /weather”路由的组件,并将其替换到 body 部分。为此,我们有一个Weather.razor组件,其中包含一些静态数据。

@page "/weather"
@attribute [StreamRendering]<PageTitle>Weather</PageTitle><h1>Weather</h1><p>This component demonstrates showing data.</p>@if (forecasts == null)
{<p><em>Loading...</em></p>
}
else
{<table class="table"><thead><tr><th>Date</th><th>Temp. (C)</th><th>Temp. (F)</th><th>Summary</th></tr></thead><tbody>@foreach (var forecast in forecasts){<tr><td>@forecast.Date.ToShortDateString()</td><td>@forecast.TemperatureC</td><td>@forecast.TemperatureF</td><td>@forecast.Summary</td></tr>}</tbody></table>
}@code {private WeatherForecast[]? forecasts;protected override async Task OnInitializedAsync(){// Simulate asynchronous loading to demonstrate streaming renderingawait Task.Delay(500);var startDate = DateOnly.FromDateTime(DateTime.Now);var summaries = new[] { "Freezing", "Bracing", "Chilly", "Cool", "Mild", "Warm", "Balmy", "Hot", "Sweltering", "Scorching" };forecasts = Enumerable.Range(1, 5).Select(index => new WeatherForecast{Date = startDate.AddDays(index),TemperatureC = Random.Shared.Next(-20, 55),Summary = summaries[Random.Shared.Next(summaries.Length)]}).ToArray();}private class WeatherForecast{public DateOnly Date { get; set; }public int TemperatureC { get; set; }public string? Summary { get; set; }public int TemperatureF => 32 + (int)(TemperatureC / 0.5556);}
}

代码片段 6:Weather.razor

如您所见,这个Weather.razor组件现在位于中心,取代了Home.razor组件。


图片 9:天气页面加载

让我检查一下该元素并向您展示它如何在浏览器中显示为单个页面。


图 10:检查天气页面上的元素

中间是 Weather.razor的代码,上方是几个

,其中一个带有类“page”,内部带有类“sidebar”。这些来自 MainLayout.razor的第 3行和第 4行。因此,最终,所有这些组件组合在一起形成一个页面。

看看下面的 GIF。请注意,单击主页和天气页面只会替换正文。


GIF 1:在主页和天气页面之间导航

各位,所有关于SSR(服务器端渲染)的讨论都归结为这一点。它是一种 Blazor 托管模型,应用程序在服务器上运行,UI 更新通过SignalR 连接发送到客户端。这正是我们在本文中看到的:每次用户请求网页时,它都会在服务器上生成并发送到客户端,然后在浏览器中呈现。

##结论
Blazor 提供了一个强大的框架,用于使用基于组件的架构构建单页应用程序。您可以创建高度交互的 Web 应用程序。关键在于了解 Blazor 如何处理用户请求并动态更新内容而无需重新加载整个页面,从而提供流畅的用户体验。

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

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

相关文章

STM32 Cannot access memory

问题描述 最近自己做了一块STM32F103ZET6的板子&#xff0c;在焊接完成后可以在下载器界面看到idcode&#xff0c;但烧录时报错 Cannot access memory 。 解决办法 测量STM32各个供电项&#xff0c;发现时33脚处VDDA电压只有1.8V&#xff0c;是因为R3电阻过大&#xff0c;…

基于YOLOv9的脑肿瘤区域检测

数据集 脑肿瘤区域检测&#xff0c;我们直接采用kaggle公开数据集&#xff0c;Br35H 数据中已对医学图像中脑肿瘤位置进行标注 数据集我已经按照YOLO格式配置好&#xff0c;数据内容如下 数据集中共包含700张图像&#xff0c;其中训练集500张&#xff0c;验证集200张 模型训…

Xilinx FPGA:vivado关于真双端口的串口传输数据的实验

一、实验内容 用一个真双端RAM&#xff0c;端口A和端口B同时向RAM里写入数据0-99&#xff0c;A端口读出单数并存入单端口RAM1中&#xff0c;B端口读出双数并存入但端口RAM2中&#xff0c;当检测到按键1到来时将RAM1中的单数读出显示到PC端&#xff0c;当检测到按键2到来时&…

YOLO V7网络实现细节(2)—网络整体架构总结

YOLO V7网络整体架构总结 YOLO v7网络架构的整体介绍 不同GPU和对应模型&#xff1a; ​​​​​​​边缘GPU&#xff1a;YOLOv7-tiny普通GPU&#xff1a;YOLOv7​​​​​​​云GPU的基本模型&#xff1a; YOLOv7-W6 激活函数&#xff1a; YOLOv7 tiny&#xff1a; leaky R…

openmetadata1.3.1 自定义连接器 开发教程

openmetadata自定义连接器开发教程 一、开发通用自定义连接器教程 官网教程链接&#xff1a; 1.https://docs.open-metadata.org/v1.3.x/connectors/custom-connectors 2.https://github.com/open-metadata/openmetadata-demo/tree/main/custom-connector &#xff08;一&…

24西安电子科技大学经济与管理学院—考研录取情况

24西安电子科技大学—经理与管理学院—考研录取统计 01、经理与管理学院各个方向 02、24经济与管理近三年复试分数线对比 1、经管院24年院线相对于23年院线普遍下降2-15分&#xff0c;个别专业上涨4-10分。 2、经管院应用经济学2024年院线350分&#xff1b;管理科学与工程院线…

Apache Seata tcc 模块源码分析

本文来自 Apache Seata官方文档&#xff0c;欢迎访问官网&#xff0c;查看更多深度文章。 本文来自 Apache Seata官方文档&#xff0c;欢迎访问官网&#xff0c;查看更多深度文章。 一 .导读 spring 模块分析中讲到&#xff0c;Seata 的 spring 模块会对涉及到分布式业务的 b…

Linux——进程间通信一(共享内存、管道、systrem V)

一、进程间通信介绍 1.1、进程间通信的概念和意义 进程间通信(IPC interprocess communication)是一组编程接口&#xff0c;让不同进程之间相互传递、交换信息(让不同的进程看到同一份资源) 数据传输:一个进程需要将它的数据发送给另外一个进程 资源共享:多个进程之间共享同样…

如何选择一家适合自己的商城源码?

商城源码的选择取决于多个因素&#xff0c;包括商城的功能需求、稳定性、易用性、可定制性以及价格等。启山智软作为在市场上被广泛认可且表现优异的商城源码提供商&#xff0c;具有以下的特点和优势&#xff1a; 特点①&#xff1a;国内知名的B2B2C开源商城源码系统&#xff…

Golang | Leetcode Golang题解之第213题打家劫舍II

题目&#xff1a; 题解&#xff1a; func _rob(nums []int) int {first, second : nums[0], max(nums[0], nums[1])for _, v : range nums[2:] {first, second second, max(firstv, second)}return second }func rob(nums []int) int {n : len(nums)if n 1 {return nums[0]}…

python conda查看源,修改源

查看源 conda config --show-sources 修改源 可以直接vim .condarc修改源&#xff0c;

vue事件处理v-on或@

事件处理v-on或 我们可以使用v-on指令&#xff08;简写&#xff09;来监听DOM事件&#xff0c;并在事件触发时执行对应的Javascript。用法&#xff1a;v-on:click"methodName"或click"hander" 事件处理器的值可以是&#xff1a; 内敛事件处理器&#xff1…

如何让代码兼容 Python 2 和 Python 3?Future 库助你一臂之力

目录 01Future 是什么? 为什么选择 Future? 安装与配置 02Future 的基本用法 1、兼容 print 函数 2、兼容整数除法 3、兼容 Unicode 字符串 03Future 的高级功能 1. 处理字符串与字节 2. 统一异常处理…

基于SpringBoot的校园台球厅人员与设备管理系统

本系统是要设计一个校园台球厅人员与设备管理系统&#xff0c;这个系统能够满足校园台球厅人员与设备的管理及用户的校园台球厅人员与设备管理功能。系统的主要功能包括首页、个人中心、用户管理、会员账号管理、会员充值管理、球桌信息管理、会员预约管理、普通预约管理、留言…

LRU缓存算法设计

LRU 缓存算法的核⼼数据结构就是哈希链表&#xff0c;双向链表和哈希表的结合体。这个数据结构⻓这样&#xff1a; 创建的需要有两个方法&#xff0c;一个是get方法&#xff0c;一个是put方法。 一些问题&#xff1a;为什么需要使用双向链表呢&#xff1f;因为删除链表的本身&…

第一节 网络安全概述

一.网络空间安全 网络空间&#xff1a;一个由信息基础设施组成相互依赖的网络。 ---- 海陆空天&#xff08;大海、陆 地、天空、航天&#xff09; 通信保密阶段 ---- 计算机安全 ----- 信息系统安全 ----- 网络空间安全 计算机安全&#xff1a;开始秉持着“严于律己&#x…

《安富莱嵌入式周报》第339期:单片机运行苹果早期Mac系统模拟器,2GHz示波器有源探头,下一代矩阵开关面包板,卡片式声音分贝器,HP经典示波器,ReRAM

周报汇总地址&#xff1a;嵌入式周报 - uCOS & uCGUI & emWin & embOS & TouchGFX & ThreadX - 硬汉嵌入式论坛 - Powered by Discuz! 视频版 https://www.bilibili.com/video/BV1Kf421Q7Lh 《安富莱嵌入式周报》第339期&#xff1a;单片机运行苹果早期Ma…

Linux开发讲课33---线程实现与线程控制步骤简析

线程概述 进程是系统中程序执行和资源分配的基本单位。 每个进程都拥有自己的数据段、代码段和堆栈段&#xff0c;这就造成了进程在进行切换等操作时都需要有比较负责的上下文切换等动作。为了进一步减少处理机的空转时间支持多处理器和减少上下文切换开销&#xff0c;进程在演…

IDEA安装IDE Eval Reset插件,30天自动续期,无限激活

第一步&#xff1a; 下载idea 注意&#xff1a;版本要是2021.2.2以下 第二步&#xff1a;快捷键CtrlAlts打开设置 第三步&#xff1a;打开下图中蓝色按钮 第四步&#xff1a;点击弹窗的 “” &#xff0c;并输入 plugins.zhile.io 点击 “ok” 第五步&#xff1a;搜索IDE Ea…

【文献解析】一种像素级的激光雷达相机配准方法

大家好呀&#xff0c;我是一个SLAM方向的在读博士&#xff0c;深知SLAM学习过程一路走来的坎坷&#xff0c;也十分感谢各位大佬的优质文章和源码。随着知识的越来越多&#xff0c;越来越细&#xff0c;我准备整理一个自己的激光SLAM学习笔记专栏&#xff0c;从0带大家快速上手激…