参考:
 Blazor 教程 - 生成首个应用
 https://dotnet.microsoft.com/zh-cn/learn/aspnet/blazor-tutorial/intro
Blazor基础知识:Visual Studio 2022 中的Blazor开发入门_vs2022 blazor webassembly-CSDN博客
 https://blog.csdn.net/mzl87/article/details/135543830
[问题解决][edge]你现在无法访问 XXX.com,因为网站使用的是 HSTS。网络错误和攻击通常是暂时的,因此该页面以后可能会恢复正常。_因为网站使用的是 hsts。网络错误和攻击通常是暂时的,因此该页面以后可能会恢复正-CSDN博客
 https://blog.csdn.net/ted_guangda/article/details/129010030
本地环境:win10, visual studio 2022 community
目录
- 创建项目
- 报错
- ResolvePackageAssets任务意外失败... NuGet unable to find fallback package folder xxx
- 启动后网页显示隐私错误 NET::ERR_CERT_INVALID
 
 
- 目录说明
- 详细说明
- 布局
- 网页
- index
- Counter
- FetchData
 
 
Blazor 使用 .NET 和 C# 构建全栈web应用,无需编写JavaScript。
创建项目
创建过程全部选默认,改动2处:
- 框架选了.Net 6.0
- 去掉了https配置(后面解释)
  
 如果找不到上图的话装一下:
  
 然后点击生成,运行:
  
报错
ResolvePackageAssets任务意外失败… NuGet unable to find fallback package folder xxx

 这个很简单,去红线所指的位置新建文件夹即可。
启动后网页显示隐私错误 NET::ERR_CERT_INVALID

 一个办法是直接在键盘输入 this is unsafe (不用打回车,就这几个字符就行)即可进入网页:
 
 这个算个后门吧,不过因为我只是在测试,直接关掉https配置即可(前面创建项目时)。
搜解决办法的时候还有人说换火狐浏览器可以,我没有测试。我这里edge和chrome都不行。
目录说明

详细说明
布局
整个网页的布局写在Shared/MainLayout.razor,如下。其中:
- @inherits LayoutComponentBase表示将从- LayoutComponentBase类继承所有功能和属性,用户可以重写以定制注入导航栏、侧边栏等组件
- <NavMenu />实际是自定义的blazor组件,参见Shared/NavMenurazor
- <article>是一个HTML标签,通常包裹一个独立的内容块
- @Body指明了主体内容在哪里。Pages下那些独立的页面会显示在这个位置
- 相关的css写在同名.css文件中
  
@inherits LayoutComponentBase
<PageTitle>BlazorApp1</PageTitle>
<div class="page">
    <div class="sidebar">
        <NavMenu />
    </div>
    <main>
        <div class="top-row px-4">
            <a href="https://docs.microsoft.com/aspnet/" target="_blank">About</a>
        </div>
        <article class="content px-4">
            @Body
        </article>
    </main>
</div>
再看一下NavMenu元件。
<div class="top-row ps-3 navbar navbar-dark">
    <div class="container-fluid">
        <a class="navbar-brand" href="">BlazorApp1</a>
        <button title="Navigation menu" class="navbar-toggler" @onclick="ToggleNavMenu">
            <span class="navbar-toggler-icon"></span>
        </button>
    </div>
</div>
<div class="@NavMenuCssClass" @onclick="ToggleNavMenu">
    <nav class="flex-column">
        <div class="nav-item px-3">
            <NavLink class="nav-link" href="" Match="NavLinkMatch.All">
                <span class="oi oi-home" aria-hidden="true"></span> Home
            </NavLink>
        </div>
        <div class="nav-item px-3">
            <NavLink class="nav-link" href="counter">
                <span class="oi oi-plus" aria-hidden="true"></span> Counter
            </NavLink>
        </div>
        <div class="nav-item px-3">
            <NavLink class="nav-link" href="fetchdata">
                <span class="oi oi-list-rich" aria-hidden="true"></span> Fetch data
            </NavLink>
        </div>
    </nav>
</div>
@code {
    private bool collapseNavMenu = true;
    private string? NavMenuCssClass => collapseNavMenu ? "collapse" : null;
    private void ToggleNavMenu()
    {
        collapseNavMenu = !collapseNavMenu;
    }
}
前面html不用看,重点看一下这句:
private string? NavMenuCssClass => collapseNavMenu ? "collapse" : null;
这句表示:如果collapseNavMenu为true,则将NavMenuCssClass设置为"collapse";否则设为null。NavMenuCssClass是侧边栏主体部分的属性,在同名.css文件中是:
@media (min-width: 641px) {
    .navbar-toggler {
        display: none;
    }
    .collapse {
        /* Never collapse the sidebar for wide screens */
        display: block;
    }
}
也就是说,当窗口宽度大于641px时,通过设置.display: block; 实现了保持导航栏折叠按钮隐藏的效果,并确保侧边栏保持展开状态,以适应较宽屏幕设备的显示效果。
 
网页
index

红圈部分对应的是:Pages/Index.razor,内容是:
@page "/"
<PageTitle>Index</PageTitle>
<h1>Hello, world!</h1>
Welcome to your new app.
<SurveyPrompt Title="How is Blazor working for you?" />
说明:
- @开头的属于c#代码,- @page指明了当前页的路径
- <PageTitle>是blazor定义的一个组件,其实就是显示在标题栏的名字,也就是上图蓝圈的文字
- <SurveyPrompt>是自定义的一个组件,放在Shared/SurveyPrompt.razor,内容是:- <div class="alert alert-secondary mt-4"> <span class="oi oi-pencil me-2" aria-hidden="true"></span> <strong>@Title</strong> <span class="text-nowrap"> Please take our <a target="_blank" class="font-weight-bold link-dark" href="https://go.microsoft.com/fwlink/?linkid=2149017">brief survey</a> </span> and tell us what you think. </div> @code { // Demonstrates how a parent component can supply parameters [Parameter] public string? Title { get; set; } }
Counter

 Counter页面多加了一个按钮,点击这个按钮,Current count: 后会更新点击次数:
 
@page "/counter"
<PageTitle>Counter</PageTitle>
<h1>Counter</h1>
<p role="status">Current count: @currentCount</p>
<button class="btn btn-primary" @onclick="IncrementCount">Click me</button>
@code {
    private int currentCount = 0;
    private void IncrementCount()
    {
        currentCount++;
    }
}
说明:
- @code表示后面的花括号里包含的是c#代码
- 页面上使用@ + 变量名就可以使用变量值
- @onclick直接使用- @code定义的函数
FetchData

 这是一个带数据模型的页面,先看 FetchData.razor :
@page "/fetchdata"
<PageTitle>Weather forecast</PageTitle>
@using BlazorApp1.Data
@inject WeatherForecastService ForecastService
<h1>Weather forecast</h1>
<p>This component demonstrates fetching data from a service.</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()
    {
        forecasts = await ForecastService.GetForecastAsync(DateTime.Now);
    }
}
说明:
- @using BlazorApp1.Data是使用这个命名空间- // Data/WeatherForecast.cs namespace BlazorApp1.Data { public class WeatherForecast { public DateTime Date { get; set; } public int TemperatureC { get; set; } public int TemperatureF => 32 + (int)(TemperatureC / 0.5556); public string? Summary { get; set; } } }
- inject是注入服务- // Data/ WeatherForecastService.cs namespace BlazorApp1.Data { public class WeatherForecastService { private static readonly string[] Summaries = new[] { "Freezing", "Bracing", "Chilly", "Cool", "Mild", "Warm", "Balmy", "Hot", "Sweltering", "Scorching" }; public Task<WeatherForecast[]> GetForecastAsync(DateTime startDate) { return Task.FromResult(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()); } } }
- @if中@表示是c#代码,直接用就行,后面- @foreach也是类似



















