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。

(本篇完)