https://blazor-university.com/学习笔记。
Introduction
What is Blazor?
原来Blazor是Browser Razor的简称。
Blazor的代码时开源的https://github.com/dotnet/aspnetcore/tree/master/src/Components,其所有者是https://dotnetfoundation.org/。
What is WebAssembly?
Wasm有点类似于.NET的中间语言 CIL(Common Intermediate Language)。
浏览器对Wasm的支持情况可以参考https://caniuse.com/#search=wasm。
Blazor hosting models
BlazorServer在2019年9月发布。BlazorWasm在2020年5月支持。
Blazor WebAssembly
BlazorWasm因为可以离线运行,特别适合于https://web.dev/progressive-web-apps/。
blazor.webassembly.js
引导客户端的启动,下载所需.NET DLL的类社(Assembly)。若采用Mono框架来诠释执行,性能会比较慢。未来会有AOT版本。BlazorWasm不支持超过一个线程,所以所有的执行都在UI线程之上。
Blazor Server
易于调试,对搜索引擎友好。但是需要消耗服务器资源,且无法在服务端之间移动会话,难以负载均衡。blazor.server.js
用于处理跟用户的交互。
客户端与服务端通过SignalR通信。SignalR运行在Websocket上,下面的一条示例消息:
DispatchBrowserEvent
{
"browserRendererId": 0,
"eventHandlerId": 3,
"eventArgsType": "mouse",
"eventFieldInfo": null
}
{
"type": "click",
"detail": 1,
"screenX": 338,
"screenY": 211,
"clientX": 338,
"clientY": 109,
"button": 0,
"buttons": 0,
"ctrlKey": false,
"shiftKey": false,
"altKey": false,
"metaKey": false
}
Blazor Mobile Bindings
使用Blazor来编写Xamarin.Forms(XAML)应用。
Installing Blazor
VS的ASP.NET and web development工作组件带有Blazor。
Creating a new project
略。
Creating a page
过。
Layouts
Layout的概念跟ASP Webforms的Master Page概念类似,跟ASP MVC中的Razor layout类似。
Layout是预定义带空槽的HTML页面。空槽供插入内容。
各个页面可以指定一个layout来囊括自己输出的内容。
Creating a Blazor layout
LayoutComponentBase是layout的基础类。layout中的@body
指示给出了空槽的位置:
@inherits LayoutComponentBase
<div class="main">
<header>
<h1>This is the header</h1>
</header>
<div class="content">
@Body
</div>
<footer>
This is the footer
</footer>
</div>
整个Blazor应用是挂载在某个HTML节点之下的。这个节点通常在wwwroot\index.html
中给定。Blazor无法修改挂载点之外的内容,除非通过JS的互操作。
Using a layout
/Pages/_Imports.razor
文件指定默认的layout:
@layout MainLayout
现在好像改成在App.razor中指定默认layout了。:
工程模板中的默认layout文件时/Shared/MainLayout.razor
。
Nested layouts
layout是通过attribute加在dotnet类之上的:
[Microsoft.AspNetCore.Components.LayoutAttribute(typeof(MainLayout))]
public class AdminUsers : Microsoft.AspNetCore.Components.ComponentBase
{
}
文中说生成的cs文件会在obj\Debug\netstandard2.0\Razor\
,可是.NET 6上貌似找不到了,估计是直接放到类社里面去了。
主要是ComponentBase的后继类型上的LayoutAttribute,Blazor都会注意到并处理之。LayoutComponentBase作为ComponentBase的后继类型之一,也可以有LayoutAttribute,这就意味着一个layout可以由另一个layout生成。
可以根据
Pages/Admin/_Imports.razor
来指定AdminUsers.razor的layout貌似不工作。
Components
所有用于渲染的Blazor视图都是从ComponentBase派生的,包括Layout, Page, 以及Component。
一个Blazor page其实是一个具有@page指示的组件,此外没有特殊之处。
可以看到Counter.razor生成的cs代码是:
namespace MyFirstBlazorApp.Client.Pages
{
[Microsoft.AspNetCore.Components.LayoutAttribute(typeof(MainLayout))]
[Microsoft.AspNetCore.Components.RouteAttribute("/counter")]
public class Counter : Microsoft.AspNetCore.Components.ComponentBase
{
protected override void BuildRenderTree(Microsoft.AspNetCore.Components.RenderTree.RenderTreeBuilder builder)
{
// Code omitted for brevity
}
private int counter = 42;
private void IncrementCounter()
{
counter++;
}
}
}
因为Page也是一个组件,所以可以直接把Page嵌入另一个Page。
Creating a component
不解,为何采用修饰名:<CreatingAComponent.Client.Components.MyFirstComponent/>
采用ILSpy查看了一下生成的DLL的内容,路径应该是
ProjectName.Components.MyFirstComponent
。
One-way binding
如果Component的文件名字中带有空格,会被转为下划线。
即便是Server端,也要求在参数上使用[ParameterAttribute]
或者[CascadingParameterAttribute]
。
好像直接用[Parameter]
也行。
当本组件刷新时,如果它的子组件带有参数,那么子组件也会被刷新。
Literals, expressions, and directives
传参的时候可以用@
下指示,比如:
<MyComponent MyParameter=42/>
<MyComponent Value=@SomeValue/>
<MyComponent @Bind-Value=SomeValue/>
上面的方式简称LED:
- Literal
- Expression
- Directive
在表达式部分使用双引号和不使用双引号的效果相同:
<MyComponent Value=@SomeValue/>
<MyComponent Value="@SomeValue"/>
参数支持默认值,如下面组件中的Visible参数:
@if (Visible)
{
<h1>@Text</h1>
}
@code
{
[Parameter]
public bool Visible { get; set; } = true;
[Parameter]
public string Text { get; set; }
}
Expression作为C#代码被调用,使用Expression的例子:
<input size=@InputSize/>
<input size=@DoubleInputSize()/>
<MyHeader Text=@HeaderText Visible=@HeaderVisible/>
更复杂的表达式可以用括弧包住,字符串的插值可以用$和花括弧处理:
<input size=@(InputSize * 3) />
<input value=@($"Size is {InputSize}") />
<input value=@($"Size is {DoubleInputSize()}") />
对于复合类型,Blazor会调用其ToString()方法将其转为字符串。也可以使用@Person?.Salutation
这种调用形式。
Blazor会对传入的表达式做一些类型推断,下面几个例子中传入的值皆和第一个的布尔值一致:
<MyComponent Visible=@true/>
<MyComponent Visible=”@true“/>
<MyComponent Visible=”true“/>
<MyComponent Visible=true/>
参数对应的辖属是字符串或者非字符串,Blazor对引号的解读是不一样的。
假设传入参数headerText的定义是string HeaderText = "Value of variable"
,接受参数的辖属是Text,定义为public string Text { get; set; }
,有下列几种情况:
<MyComponent Text=”Hello”/>
,接受的是字符串"Hello"
。<MyComponent Text=@HeaderText/>
,接收的是HeaderText的值"Value of variable"。<MyComponent Text=”HeaderText”/>
,接收的是字符串"HeaderText"
。<MyComponent Text=HeaderText/>
,接受的是字符串"HeaderText"
Visual Studio会以不用的颜色来区分Expression和非expression。
(本篇完)