1. 第一个应用
1. 创建项目

1.1. 运行项目

2. 修改项目
2.1. 添加内容
- 在根目录下添加一个名为Features的新文件。
- 在该文件夹中下创建Common文件夹,将原来的NotFound.razor文件移动到这里
- 再次在该文件夹中,添加一个名为 Layout 的文件夹和另一个名为 Home 的文件夹。
- 在 Layout 中,添加一个名为 MainLayout.razor 的新 Blazor 组件。
- 在 Home 中,添加一个名为 HomePage.razor 的新 Blazor组件。
- 完成此作后,返回到 _Imports.razor 并添加以下 using 语句:
@using BlazingTrails.Client.Features.Home
@using BlazingTrails.Client.Features.Layout

2.2 默认布局
布局中包含页眉、页脚和导航菜单等内容,它来自于LayoutComponentBase基类,常见的布局内容如下所示

- 默认布局在Router组件中定义。
<Router AppAssembly="typeof(Program).Assembly" NotFoundPage="typeof(NotFound)" >
<Found Context="routeData">
<RouteView RouteData="routeData" DefaultLayout="typeof(MainLayout)"/>
<FocusOnNavigate RouteData="routeData" Selector="h1"/>
</Found>
</Router>
- 在此之前需要在_Imports.razor文件中添加命名空间引用
@using MyBlazingTrals.Components.Features.Common
@using MyBlazingTrals.Components.Features.Layout
- 修改MainLayout布局
@inherits LayoutComponentBase
<main class="container my-5">
@Body
</main>
- 添加Header组件
<nav class="navbar mb-5 shadow">
<a class="navbar-brand" href="/">
MyBlazingTrals
</a>
</nav>
- 完善MainLayout
@inherits LayoutComponentBase
<Header></Header>
<main class="container my-5">
@Body
</main>
2.3. 删除不需要的内容
- Pages文件夹及其内容
- Layout文件夹及其内容
2.4 修改Home页面
@page "/"
<PageTitle>Blazing Trails</PageTitle>
<h1>HomePage</h1>
@code {
}
2.4.1 添加Trial实体类
namespace MyBlazingTrals.Components.Features.Home;
/// <summary>
/// 实体类:徒步路线
/// </summary>
public class Trail
{
public int Id { get; set; }
public string Name { get; set; } = "";
public string Description { get; set; } = "";
public string Image { get; set; } = "";
public string Location { get; set; } = "";
public int TimeInMinutes { get; set; }
public string TimeFormatted => $"{TimeInMinutes / 60}h {TimeInMinutes % 60}m";
public int Length { get; set; }
public IEnumerable<RouteInstruction> Route { get; set; } =
Array.Empty<RouteInstruction>();
}
/// <summary>
/// 线路上的导航点
/// </summary>
public class RouteInstruction
{
public int Stage { get; set; }
public string Description { get; set; } = "";
}
2.4.2 添加测试数据
- 在wwwroot中添加trails文件夹
- 添加trail-data.json文件并在其中添加测试数据
[
{
"id": 1,
"image": "trails/1.jpg",
"name": "Countryside Ramble",
"location": "Durbach, Germany",
"timeInMinutes": 195,
"length": 11,
"description": "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nulla volutpat orci at augue ultricies fermentum. Ut massa lectus, dignissim sed molestie ut, viverra vel diam. Fusce at iaculis magna. Suspendisse vel est et est luctus ornare venenatis ut neque. Pellentesque varius lacus sed arcu pellentesque, a porttitor velit gravida. Nunc nunc lectus, rhoncus consectetur metus eget, fermentum laoreet mauris. Cras ac gravida ante. Ut in ante ex. Proin tristique a ligula vel pharetra. Vestibulum blandit nisl dui, in pulvinar metus mollis pharetra. Duis cursus porttitor libero, quis lacinia velit. Curabitur tincidunt laoreet mi, eu maximus nibh vestibulum sed. Phasellus orci.",
"route": [
{
"stage": 1,
"description": "Lorem ipsum dolor sit amet, consectetur adipiscing elit."
},
{
"stage": 2,
"description": "Curabitur interdum molestie tempus."
},
{
"stage": 3,
"description": "Suspendisse convallis nunc ut lorem cursus, ac venenatis neque maximus."
},
{
"stage": 4,
"description": "Aenean nisi dolor, sollicitudin quis pellentesque vel, pharetra et ex."
},
{
"stage": 5,
"description": "Vestibulum vulputate velit quis mi suscipit, eget pharetra enim tristique."
}
]
},
{
"id": 2,
"image": "trails/2.jpg",
"name": "Woodland Walk",
"location": "Nottingham, UK",
"timeInMinutes": 80,
"length": 4,
"description": "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vivamus a semper lacus. Vestibulum vehicula elementum auctor. Vestibulum malesuada, nibh a pretium ullamcorper, tortor nisi tincidunt ante, sed gravida purus mi in ligula. In malesuada ligula vitae risus iaculis, et sollicitudin lorem ornare. Nullam nec ullamcorper est. Donec efficitur et ipsum auctor semper. In id eros risus. Suspendisse quis massa convallis, suscipit eros eget, ullamcorper metus. Phasellus laoreet nulla quam, vel porttitor diam efficitur vitae. Etiam sollicitudin urna vel auctor accumsan. Suspendisse commodo pulvinar mauris, quis viverra lectus hendrerit dictum. In sed lorem tempus ipsum rutrum suscipit vitae sed mauris. Nunc.",
"route": [
{
"stage": 1,
"description": "Lorem ipsum dolor sit amet, consectetur adipiscing elit."
},
{
"stage": 2,
"description": "Curabitur interdum molestie tempus."
},
{
"stage": 3,
"description": "Suspendisse convallis nunc ut lorem cursus, ac venenatis neque maximus."
},
{
"stage": 4,
"description": "Aenean nisi dolor, sollicitudin quis pellentesque vel, pharetra et ex."
},
{
"stage": 5,
"description": "Vestibulum vulputate velit quis mi suscipit, eget pharetra enim tristique."
}
]
},
{
"id": 3,
"image": "trails/3.jpg",
"name": "Alpine Hike",
"location": "Furna, Switzerland",
"timeInMinutes": 150,
"length": 6,
"description": "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Curabitur vel purus fringilla, rhoncus nulla et, dapibus quam. Phasellus pulvinar ex quis laoreet vulputate. Aliquam tempor faucibus diam sit amet mattis. Sed hendrerit, mi quis placerat pellentesque, ante odio dictum tellus, et luctus ex justo eget ante. Sed sit amet nulla dictum, hendrerit sem at, rutrum mi. Vestibulum quis sodales odio, finibus porttitor turpis. Etiam magna nibh, ornare sit amet suscipit laoreet, mattis ut orci. Curabitur a auctor lectus. Nullam eget volutpat felis, eu blandit ante. Nam ligula nisi, euismod at fringilla et, vulputate ut lectus. Nulla facilisi. Vestibulum ante ipsum.",
"route": [
{
"stage": 1,
"description": "Lorem ipsum dolor sit amet, consectetur adipiscing elit."
},
{
"stage": 2,
"description": "Curabitur interdum molestie tempus."
},
{
"stage": 3,
"description": "Suspendisse convallis nunc ut lorem cursus, ac venenatis neque maximus."
},
{
"stage": 4,
"description": "Aenean nisi dolor, sollicitudin quis pellentesque vel, pharetra et ex."
},
{
"stage": 5,
"description": "Vestibulum vulputate velit quis mi suscipit, eget pharetra enim tristique."
}
]
},
{
"id": 4,
"image": "trails/4.jpg",
"name": "Bridge to Nowhere",
"location": "Gearstones, UK",
"timeInMinutes": 320,
"length": 14,
"description": "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Ut imperdiet ex ac euismod pulvinar. Cras lorem nulla, posuere sed semper sed, scelerisque non nulla. Sed mi lorem, condimentum nec magna ac, ultricies lobortis ante. Integer tincidunt, metus eget mattis hendrerit, nibh metus sagittis diam, sed imperdiet metus nisi ac magna. Pellentesque iaculis mi purus, a porta tortor sodales consequat. Pellentesque vel mattis ligula. Fusce ac massa id ex rutrum eleifend. Nunc porta tortor dictum, ornare metus quis, laoreet ante. Nullam ullamcorper magna eget eleifend consequat. In nulla ex, iaculis vestibulum eros ac, vestibulum euismod arcu. Nullam sollicitudin at neque et.",
"route": [
{
"stage": 1,
"description": "Lorem ipsum dolor sit amet, consectetur adipiscing elit."
},
{
"stage": 2,
"description": "Curabitur interdum molestie tempus."
},
{
"stage": 3,
"description": "Suspendisse convallis nunc ut lorem cursus, ac venenatis neque maximus."
},
{
"stage": 4,
"description": "Aenean nisi dolor, sollicitudin quis pellentesque vel, pharetra et ex."
},
{
"stage": 5,
"description": "Vestibulum vulputate velit quis mi suscipit, eget pharetra enim tristique."
}
]
},
{
"id": 5,
"image": "trails/5.jpg",
"name": "Costal Walk",
"location": "Ockle, Scotland",
"timeInMinutes": 105,
"length": 5,
"description": "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Ut laoreet, justo ut egestas pulvinar, est dui elementum neque, ac elementum lectus tellus in libero. Cras ullamcorper tellus id velit finibus, at rutrum odio convallis. Donec gravida nec mauris eget iaculis. Praesent faucibus ante fringilla, ullamcorper enim sit amet, suscipit leo. Sed libero erat, facilisis vel nunc et, venenatis volutpat quam. Integer sit amet lobortis risus, ut hendrerit orci. Vivamus pulvinar lectus dui, a dictum odio eleifend vitae. Pellentesque gravida risus eu ipsum efficitur consectetur. Nulla lectus leo, pharetra vel ante ut, mollis pharetra arcu. Morbi vitae metus ante. Integer lacinia.",
"route": [
{
"stage": 1,
"description": "Lorem ipsum dolor sit amet, consectetur adipiscing elit."
},
{
"stage": 2,
"description": "Curabitur interdum molestie tempus."
},
{
"stage": 3,
"description": "Suspendisse convallis nunc ut lorem cursus, ac venenatis neque maximus."
},
{
"stage": 4,
"description": "Aenean nisi dolor, sollicitudin quis pellentesque vel, pharetra et ex."
},
{
"stage": 5,
"description": "Vestibulum vulputate velit quis mi suscipit, eget pharetra enim tristique."
}
]
},
{
"id": 6,
"image": "trails/6.jpg",
"name": "Through the valleys",
"location": "Tryfan, Wales",
"timeInMinutes": 290,
"length": 13,
"description": "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Integer facilisis magna eget sem feugiat, non pulvinar dui interdum. Proin quis tincidunt ex. Pellentesque dictum nibh dolor, cursus porta magna sodales a. Morbi vitae tortor nisi. Nullam molestie dui tempus, lobortis dolor sit amet, hendrerit libero. Quisque sed massa id lacus ornare faucibus eget facilisis mi. Donec interdum bibendum leo nec facilisis. In semper nec eros id tincidunt. Nunc sed sagittis justo. Ut massa ligula, posuere sed iaculis sit amet, laoreet ut ipsum. Nulla facilisi. Vestibulum iaculis risus nulla. Nunc congue elit et erat blandit vulputate. Praesent vulputate tortor at augue.",
"route": [
{
"stage": 1,
"description": "Lorem ipsum dolor sit amet, consectetur adipiscing elit."
},
{
"stage": 2,
"description": "Curabitur interdum molestie tempus."
},
{
"stage": 3,
"description": "Suspendisse convallis nunc ut lorem cursus, ac venenatis neque maximus."
},
{
"stage": 4,
"description": "Aenean nisi dolor, sollicitudin quis pellentesque vel, pharetra et ex."
},
{
"stage": 5,
"description": "Vestibulum vulputate velit quis mi suscipit, eget pharetra enim tristique."
}
]
},
{
"id": 7,
"image": "trails/7.jpg",
"name": "Mountian Lakes",
"location": "Scafell Pike, UK",
"timeInMinutes": 205,
"length": 11,
"description": "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vestibulum pellentesque metus purus, fermentum bibendum turpis ornare et. Duis pellentesque libero vitae tortor sagittis placerat. Suspendisse consectetur rhoncus lectus et dignissim. Proin iaculis urna nec justo pellentesque, a posuere dolor aliquam. Sed quam sapien, fermentum non nisl eget, faucibus fermentum purus. Donec ut est quis sem imperdiet rhoncus. Nunc in porta lectus, eget lacinia velit. Cras dui ipsum, dictum ut mauris nec, euismod accumsan ligula. Vestibulum eget sapien scelerisque, feugiat nibh non, ornare quam. Aenean semper, lectus id gravida consequat, nisl metus suscipit nulla, a placerat purus ante ut nunc. Aliquam.",
"route": [
{
"stage": 1,
"description": "Lorem ipsum dolor sit amet, consectetur adipiscing elit."
},
{
"stage": 2,
"description": "Curabitur interdum molestie tempus."
},
{
"stage": 3,
"description": "Suspendisse convallis nunc ut lorem cursus, ac venenatis neque maximus."
},
{
"stage": 4,
"description": "Aenean nisi dolor, sollicitudin quis pellentesque vel, pharetra et ex."
},
{
"stage": 5,
"description": "Vestibulum vulputate velit quis mi suscipit, eget pharetra enim tristique."
}
]
},
{
"id": 8,
"image": "trails/8.jpg",
"name": "Forest Trek",
"location": "Clayhill, UK",
"timeInMinutes": 185,
"length": 10,
"description": "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nulla maximus nulla et urna convallis tempus. Nunc ipsum sapien, bibendum quis dapibus ut, feugiat at neque. Nunc non ipsum iaculis, imperdiet risus ut, egestas nunc. Donec quis mattis est, quis ultrices erat. Fusce aliquet, massa sed dignissim sollicitudin, turpis diam venenatis nisl, ac mattis lacus nunc vel leo. Vestibulum vitae dignissim mi, quis placerat magna. Proin dignissim at ante ac posuere. Integer finibus tincidunt mollis. Pellentesque varius sed justo vitae eleifend. Mauris et risus tortor. Maecenas massa ipsum, dignissim nec ipsum a, sagittis sodales tellus. Nullam rutrum malesuada libero vel posuere.",
"route": [
{
"stage": 1,
"description": "Lorem ipsum dolor sit amet, consectetur adipiscing elit."
},
{
"stage": 2,
"description": "Curabitur interdum molestie tempus."
},
{
"stage": 3,
"description": "Suspendisse convallis nunc ut lorem cursus, ac venenatis neque maximus."
},
{
"stage": 4,
"description": "Aenean nisi dolor, sollicitudin quis pellentesque vel, pharetra et ex."
},
{
"stage": 5,
"description": "Vestibulum vulputate velit quis mi suscipit, eget pharetra enim tristique."
}
]
},
{
"id": 9,
"image": "trails/9.jpg",
"name": "Open Countryside",
"location": "Long Stratton, UK",
"timeInMinutes": 50,
"length": 2,
"description": "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Suspendisse quis orci vitae nulla fringilla aliquet. Suspendisse vel tincidunt mi. Donec eu augue nec massa feugiat fermentum. In malesuada dui at risus tristique commodo. Morbi varius leo vitae lectus tincidunt rhoncus. Nam hendrerit fringilla ipsum, nec pellentesque justo congue ut. Fusce pulvinar risus tincidunt scelerisque viverra. Fusce cursus arcu sed lectus porttitor faucibus. Donec imperdiet elementum interdum. Suspendisse sed bibendum est. Aenean pulvinar purus quis aliquet interdum. Vivamus sit amet iaculis ante, vitae facilisis lorem. Cras in tortor et orci feugiat vulputate at eget elit. In eget diam blandit, dignissim nibh.",
"route": [
{
"stage": 1,
"description": "Lorem ipsum dolor sit amet, consectetur adipiscing elit."
},
{
"stage": 2,
"description": "Curabitur interdum molestie tempus."
},
{
"stage": 3,
"description": "Suspendisse convallis nunc ut lorem cursus, ac venenatis neque maximus."
},
{
"stage": 4,
"description": "Aenean nisi dolor, sollicitudin quis pellentesque vel, pharetra et ex."
},
{
"stage": 5,
"description": "Vestibulum vulputate velit quis mi suscipit, eget pharetra enim tristique."
}
]
}
]
2.4.3 在Home页面中获取数据
通过HttpClient来获取json数据,这里采用依赖注入方式获取。
语法如下
@inject [TYPE] [NAME]
[Type] 是我们所需的对象的类型,
[Name] 是我们将用于在组件中使用该实例
的名称。
注入结果如下:
@page "/"
@inject HttpClient Http
<PageTitle>Blazing Trails</PageTitle>
<h1>HomePage</h1>
@code {
private IEnumerable<Trail> _trails;
}
注意:
如果是Server模版创建的项目,默认不会注册HttpClient,所以要在program.cs中手动注册
// 注册 HttpClient,使用 NavigationManager 提供 BaseAddress(适用于 Blazor Server)
builder.Services.AddScoped(sp =>
{
var nav = sp.GetRequiredService<Microsoft.AspNetCore.Components.NavigationManager>();
return new HttpClient { BaseAddress = new Uri(nav.BaseUri) };
});
Blazor中附带一组增强的HttpClient方法:
- GetFromJsonAsync
<T> - PostAsJsonAsync
- PutAsJsonAsync
@code {
private IEnumerable<Trail>? _trails;
protected override async Task OnInitializedAsync()
{
try
{
_trails = await Http
.GetFromJsonAsync<IEnumerable<Trail>>
("trails/trail-data.json");
}
catch (HttpRequestException ex)
{
Console.WriteLine($"There was a problem loading trail data: {ex.Message}");
}
}
}
2.4.4 展示数据
@page "/"
@inject HttpClient Http
<PageTitle>Blazing Trails</PageTitle>
@if (_trails == null)
{
<p>Loading...</p>
}
else
{
<div class="container">
<div class="row">
@foreach (var trail in _trails)
{
<div class="col-3 card shadow m-5 p-0">
<img src="@trail.Image" class="card-img-top" alt="@trail.Name">
<div class="card-body">
@* 标题 *@
<h5 class="card-tiele">@trail.Name</h5>
@* 位置 *@
<h6 class="card-subtitle mb-5 text-muted">
<span class="bi bi-geo">@trail.Location</span>
</h6>
@* 描述 *@
<div class="d-flex justify-content-between">
@* 时间 *@
<span>
<span class="bi bi-clock mr-2"></span>
@trail.TimeFormatted
</span>
@* 路程 *@
<span>
<span class="bi bi-infinity mr-2"></span>
@trail.Length km
</span>
</div>
</div>
</div>
}
</div>
</div>
}
@code {
private IEnumerable<Trail>? _trails;
protected override async Task OnInitializedAsync()
{
try
{
_trails = await Http
.GetFromJsonAsync<IEnumerable<Trail>>
("trails/trail-data.json");
}
catch (HttpRequestException ex)
{
Console.WriteLine($"There was a problem loading trail data: {ex.Message}");
}
}
}
2.4.5 使用组件
- 为了简化代码,可以将复用的部分封装成组件
在Home feture文件夹中创建TrailCard.razor组件 - 可以通过Parameter特性来传递从外部传递参数
- 使用EditorRequired特性表示这个参数是必需的
<div class="col-3 card shadow m-5 p-0">
<img src="@Trail.Image" class="card-img-top" alt="@Trail.Name">
<div class="card-body">
@* 标题 *@
<h5 class="card-tiele">@Trail.Name</h5>
@* 位置 *@
<h6 class="card-subtitle mb-5 text-muted">
<span class="bi bi-geo">@Trail.Location</span>
</h6>
@* 描述 *@
<div class="d-flex justify-content-between">
@* 时间 *@
<span>
<span class="bi bi-clock mr-2"></span>
@Trail.TimeFormatted
</span>
@* 路程 *@
<span>
<span class="bi bi-infinity mr-2"></span>
@Trail.Length km
</span>
</div>
</div>
</div>
@code
{
[Parameter,EditorRequired]
public Trail Trail { get; set; }
}
- 在Home页面中更新为组件
@page "/"
@inject HttpClient Http
<PageTitle>Blazing Trails</PageTitle>
@if (_trails == null)
{
<p>Loading...</p>
}
else
{
<div class="container">
<div class="row">
@foreach (var trail in _trails)
{
<TrailCard Trail="trail" />
}
</div>
</div>
}
@code {
private IEnumerable<Trail>? _trails;
protected override async Task OnInitializedAsync()
{
try
{
_trails = await Http
.GetFromJsonAsync<IEnumerable<Trail>>
("trails/trail-data.json");
}
catch (HttpRequestException ex)
{
Console.WriteLine($"There was a problem loading trail data: {ex.Message}");
}
}
}
2.4.6 最终效果

浙公网安备 33010602011771号