.NET 平台的前端框架,使用C#和HTML构建
ASP.NET Core Blazor 简介
★Blazor UI库
Blazor的两种方式
WebAssembly
应用于客户端,在第一次访问的时候就把预编译好的代码,下载到客户端的浏览器里面,然后就在客户端的浏览器运行了。
可以运行在所有的浏览器上面。
部署可以不用.NET。是个web服务器就行
拥有SPA体验。
老浏览器不支持。
第一次下载可能有点大。
Server
服务端的Blazor是在一个ASP.NET Core里面。客户端访问了服务端后,他们之间的通信使用SignalR进行通信。
需要下载的东西比较小。
可以使用所有服务器端的API。
有完整的Debug体验。
任何浏览器都可以运行
项目结构
ASP.NET Core Blazor 项目结构
这是用vs2019创建的blazor wasm应用,勾了ASP.NET Core的项目结构
Pages文件夹:里面放的都是Blazor的可路由的组件或者页面,和Vue组件一样 Shared文件夹: 包含共享的组件和样式表
运行方式
在wwwroot静态文件里面有个index.html,里面有个div的id是app
<body>
<div id="app">Loading...</div>
<div id="blazor-error-ui">
An unhandled error has occurred.
<a href="" class="reload">Reload</a>
<a class="dismiss">🗙</a>
</div>
<script src="_framework/blazor.webassembly.js"></script>
</body>
在Program.cs文件中(应用入口),把根组件App添加到index.html里面的id为app的标签里面。用根节点App替换#app里面的内容
public static async Task Main(string[] args)
{
var builder = WebAssemblyHostBuilder.CreateDefault(args);
builder.RootComponents.Add<App>("#app");
builder.Services.AddScoped(sp => new HttpClient { BaseAddress = new Uri(builder.HostEnvironment.BaseAddress) });
await builder.Build().RunAsync();
}
而根节点App如下,外层就是路由组件,如果url有这个路由,就会把相应路由的组件放到Found组件里面RouteView组件里面,默认用了一个MainLayout布局页面。
当然如果没有找到这个url的路由组件,就会显示NotFound里面的东西
<Router AppAssembly="@typeof(Program).Assembly" PreferExactMatches="@true">
<Found Context="routeData">
<RouteView RouteData="@routeData" DefaultLayout="@typeof(MainLayout)" />
</Found>
<NotFound>
<LayoutView Layout="@typeof(MainLayout)">
<p>Sorry, there's nothing at this address.</p>
</LayoutView>
</NotFound>
</Router>
路由
在每个组件的最上面写路由
一个组件可以用多个路由,这些路由访问同一个组件。
@page "/"
@page "/index"
@page "/A"
<h1>Hello, world!</h1>
Welcome to your new app.
<SurveyPrompt Title="How is Blazor working for you?" />
路由参数
路由可以加一个参数,用花括号括起来,C#代码需要一个属性来接收这个参数,用特性Parameter标识。如果路由不带这个参数,访问不到。
@page "/counter/{Count}"
<h1>Counter</h1>
<p>Count: @Count</p>
<button class="btn btn-primary" @onclick="IncrementCount">Click me</button>
@code {
private int currentCount = 0;
[Parameter]
public string Count { get; set; }
private void IncrementCount()
{
currentCount++;
}
}
不限制路由参数的都是string类型。可以用{参数名:参数类型}
来限定路由参数是什么类型的
@page "/counter/{Count:int}"
URL和导航状态
通过NavigationManager类来管理Url和导航
@page "/counter/{Count:int}"
@inject NavigationManager NavigationManager
<h1>Counter</h1>
<p>Count: @Count</p>
<button class="btn btn-primary" @onclick="IncrementCount">Click me</button>
@code {
private int currentCount = 0;
[Parameter]
public int Count { get; set; }
private void IncrementCount()
{
currentCount++;
}
protected override void OnInitialized()
{
//获取查询字符串,需要先注册组件
//其他用法看文档
var query = new Uri(NavigationManager.Uri).Query;
}
}
NavLink
和a标签一样,用这个标签路由到其他页面,href地址就是路由地址
<NavLink class="nav-link" href="counter">
<span class="oi oi-plus" aria-hidden="true"></span> Counter
</NavLink>
依赖注入
ASP.NET Core Blazor 依赖关系注入
有几个默认注册的类,看文档。
自己注册在Program类里面注册,使用注册的服务,在组件页面上面@inject 注册服务类型 使用服务时的属性名
组件
ASP.NET Core 的 Razor 语法参考
ASP.NET Core Razor 组件
组件是使用 C# 和 HTML 标记的组合在 Razor 组件文件(文件扩展名为 .razor)中实现的
组件名称必须以大写字母开头
代码分离
组件里面有C#的代码,把分离到单独的类文件
这是原本组件的代码
@page "/counter"
<h1>Counter</h1>
<p>Current count: @currentCount</p>
<button class="btn btn-primary" @onclick="IncrementCount">Click me</button>
@code {
private int currentCount = 0;
private void IncrementCount()
{
currentCount++;
}
}
在当前组件文件夹里面新建一个类,和组件同名,后缀加上.cs
把code里面代码拷贝进去,这是个部分类
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
namespace Blog6.Client.Pages
{
public partial class Counter
{
private int currentCount = 0;
private void IncrementCount()
{
currentCount++;
}
}
}
现在.razor页面里面就不用写C#代码了,全部写到单独的部分类里面
组件传参
组件之间可以互相嵌套。
这是定义了一个子组件
<h3>@Name</h3>
<h3>@Age</h3>
<h3>@Score</h3>
@code {
[Parameter]
public string Name { get; set; }
[Parameter]
public int Age { get; set; }
[Parameter]
public double Score { get; set; }
}
在父组件中调用子组件,给子组件传参
@page "/"
<h1>Hello, world!</h1>
Welcome to your new app.
@*在当前组件用子组件*@
@*这是第一种属性传参*@
<New Name="张三" Age="12" Score="98.5"/>
@*第二种传多个参数用字典的形式*@
<New @attributes="kv"/>
@code{
//
public Dictionary<string, object> kv { get; set; } = new Dictionary<string, object>()
{
{ "Name","李四" },
{"Age",14 },
{"Score",59.5 }
};
}
子组件方法在父组件里执行
就是子组件用回调函数
在父组件里面嵌套子组件,这个子组件就是一个输入框和按钮,输入框绑定了值。 子组件声明了一个回调函数属性,就把他看成一个属性。 在父组件给这个子组件的属性OnSearch传参数,只不过这个参数是一个在父组件定义的方法。 现在这个方法传给了子组件的OnSearch属性。 当点击“搜索”按钮时,子组件执行方法SearchText,但是这个方法里面没有具体的方法实现,OnSearch属性是一个方法,我在SearchText里面调用OnSearch方法。而OnSearch的方法是父组件传过来,具体实现在父组件定义。 最后点击了按钮,执行的函数是父组件的SSS
这是子组件
<input type="text" @bind-value="@Value" />
<a @onclick="SearchText">搜索</a>
@code
{
public string Value { get; set; }
//这是个回调函数
[Parameter]
public EventCallback<string> OnSearch { get; set; }
public void SearchText()
{
OnSearch.InvokeAsync(Value);
}
}
这是父组件
@page "/"
<h1>Hello, world!</h1>
Welcome to your new app.
<Search OnSearch="SSS" />
@code
{
public void SSS(string text)
{
//最终执行的回调
}
}
生命周期
ASP.NET Core Razor 组件生命周期
Blazor的生命周期与React组件的生命周期类似,也分为三个阶段:初始化阶段、运行中阶段和销毁阶段,其相关方法有10个,包括设置参数前、初始化、设置参数之后、组件渲染后以及组件的销毁,但是这些方法有些是重复的,只不过是同步与异步的区别
1 | 每次参数注入时或在父级被修改时调用。即从父级传过来的参数,或者祖先级传过来的级联参数,或者路由参数。在初始化之前,接受一个ParameterView类型参数 | SetParametersAsync |
---|---|---|
2 | 初始化,参数注入完成后 | OnInitialized/OnInitializedAsync |
3 | 每次参数设置之后调用,完成之后开始渲染组件,如果是异步则等待完成后渲染 | OnParametersSet/OnParametersSetAsync |
4 | 每次渲染结束后调用,接受一个参数firstRender表示是否是首次渲染,只有在首次渲染是是true,其余均是false。 | OnAfterRender/OnAfterRenderAsync |
5 | 除了首次,每次渲染完成后调用,返回一个bool值,表示是否进行渲染 | ShouldRender |
6 | 组件销毁前调用 | Dispose |
7 | 状态更改时调用 | StateHasChanged |
CSS隔离
给每个组件设置CSS,和部分类一样,组件全名加个.css
比如这样
布局
默认布局
当没有为组件指定特定布局时,路由到这个组件,就会用App的默认布局
<Router AppAssembly="@typeof(Program).Assembly" PreferExactMatches="@true">
<Found Context="routeData">
<RouteView RouteData="@routeData" DefaultLayout="@typeof(MainLayout)" />
</Found>
<NotFound>
<LayoutView Layout="@typeof(MainLayout)">
<p>Sorry, there's nothing at this address.</p>
</LayoutView>
</NotFound>
</Router>
<AntContainer />
自定义布局
在布局文件夹里面新建一个.razor
文件。里面写布局页面的框架。
最上方写@inherits LayoutComponentBase
表示继承自LayoutComponentBase ,说明这是个母版页,使@Body作为占位,组件就显示在这里。
@inherits LayoutComponentBase
<div class="page">
<div class="sidebar">
<NavMenu />
</div>
<div class="main">
<div class="top-row px-4">
<a href="http://blazor.net" target="_blank" class="ml-md-auto">About</a>
</div>
<div class="content px-4">
@Body
</div>
</div>
</div>
然后在需要自定义布局页的组件上面写@layout 模板页名
,这样路由到这个页面就会使用这个自定义的布局页面
@page "/"
@layout 模板页名
<h1>Hello, world!</h1>
Welcome to your new app.