Blazor 和 WebAssembly





5.00/5 (3投票s)
Blazor 和 WebAssembly 示例(Blazor 演示文稿的一部分)
获取您的 免费 Azure 账户
此存储库包含使用 Blazor 的 WebAssembly,在浏览器中使用 C# 和 .NET 的演示示例。
👋🏻 Blazor 介绍/概述
<g-emoji class="g-emoji" alias="hocho" fallback-src="https://github.githubassets.com/images/icons/emoji/unicode/1f52a.png">🔪 Razor 组件介绍
此存储库使用免费的 Azure Pipelines 进行持续构建和部署。如果您对如何设置和配置自动构建以及部署到低成本 Azure 存储静态网站感兴趣,请阅读 使用 Azure Pipelines 将 WebAssembly 从 GitHub 部署到 Azure 存储静态网站。
演示文稿
<g-emoji class="g-emoji" alias="cinema" fallback-src="https://github.githubassets.com/images/icons/emoji/unicode/1f3a6.png">🎦 您可以在 此处 下载相关的 PowerPoint 演示文稿。
要了解 Blazor 与 Angular 等其他 SPA 框架的对比,请阅读: Angular vs. Blazor。
演示
本节包含执行每个演示的分步说明。
先决条件
要使演示正常工作,应安装以下软件
- 用于
asm.js
和 WebAssembly 演示的 emscripten - 用于提供“primes”示例站点的 http-service (node.js)(任何简单的 Web 服务器即可)
- Blazor 提供了完整的安装和使用说明,请访问 Blazor。
此存储库当前使用的版本是 3.0.0-preview9.19424.4
。
构建 asm.js
进入 primes 目录。首先,展示 JavaScript 版本的速度。
cat primes-js.js
node primes-js.js
接下来,展示 C 代码。
cat primes.c
然后,将 C 代码编译为 asm.js
emcc primes.asm.c -s WASM=0 -Os -o primes.asm.js
为了便于参考,显示展开的代码,然后运行 asm.js 版本
cat primes-asm.js
node primes-asm.js
构建 WebAssembly (Wasm)
<g-emoji class="g-emoji" alias="eyes" fallback-src="https://github.githubassets.com/images/icons/emoji/unicode/1f440.png">👀 实时演示
显示 C 代码
cat primes.wasm.c
将 C 代码编译为 WebAssembly
emcc primes.wasm.c -s WASM=1 -Os -o primes.wasm.js
使用像 http-server
这样的简单服务器来提供目录中的文件。导航到 primes.html
打开控制台,显示 JavaScript 与 WebAssembly 的时间对比。
入门
创建一个新的带有 .NET Core 托管的 Blazor 项目。运行应用程序并逐步浏览各个选项卡。
- 注意,返回时计数器会重置为零。
- 显示
Shared
项目定义了一个在客户端和服务器之间共享的WeatherForecast
类。 - 演示
Startup
中的服务注册。 - 在客户端上打开
Startup
以配置类似的服务。 - 逐步讲解
Counter.razor
的逻辑。 - 指出
FetchData.razor
使用HttpClient
,但它已注入以获得正确的配置。 - 在浏览器中激活网络调试。刷新并显示正在加载的 DLL。
可重用组件
<g-emoji class="g-emoji" alias="eyes" fallback-src="https://github.githubassets.com/images/icons/emoji/unicode/1f440.png">👀 实时演示
创建一个新的 Blazor 项目(无托管,仅客户端)。
在
Shared
下创建一个 Razor 视图组件,并将其命名为LabelSlider.razor
。粘贴以下 HTML。
<input type="range" min="@Min" max="@Max" @bind="@CurrentValue" /> <span>@CurrentValue</span>
在
@code
块中添加。[Parameter] public int Min { get; set; } [Parameter] public int Max { get; set; } [Parameter] public int CurrentValue { get; set; }
将其添加到
Counter
页面。<LabelSlider Min="0" Max="99" CurrentValue="@currentCount"/>
展示单击如何更新滑块,但滑动不会更新宿主页面。还要注意,值仅在您停止滑动时更新,并且仅在滑块上更新,而不是在“当前计数”上更新(尽管单击按钮会更新滑块,反之则不然)。
在
LabelSlider
中,将绑定更改为@bind-value="@CurrentValue"
,然后添加额外的@bind-value:event="oninput"
以在滑动时刷新。添加一个用于当前值更改的事件并实现它(这将替换现有的
CurrentValue
属性)。private int _currentValue; [Parameter] public int CurrentValue { get => _currentValue; set { if (value != _currentValue) { _currentValue = value; CurrentValueChanged?.Invoke(value); } } } [Parameter] public Action<int> CurrentValueChanged { get; set; }
在
Counter.razor
中将绑定更新为@bind-CurrentValue
。运行并显示它正在获取值,但没有刷新。解释我们稍后将介绍手动 UI 刷新。
库和互操作
<g-emoji class="g-emoji" alias="eyes" fallback-src="https://github.githubassets.com/images/icons/emoji/unicode/1f440.png">👀 实时演示
创建一个新的仅客户端项目。
在 NuGet 包中,搜索并安装
Markdown
,请访问 此处。在
Index.razor
中添加以下 HTML(删除SurveyPrompt
)。<textarea style="<span class="pl-c1"><span class="pl-c1">width: 100%</span>"</span> rows="5" @bind="@SourceText"></textarea> <button @onclick="@Convert">Convert</button> <p>@TargetText</p>
在顶部添加
@using HeyRed.MarkdownSharp
。添加一个
@code
块。string SourceText { get; set; } string TargetText { get; set; } Markdown markdown = new Markdown(); void Convert() { TargetText = markdown.Transform(SourceText); }
运行并展示转换。解释绑定是“安全的”,不会展开 HTML。
在
wwwroot
下创建一个名为markupExtensions.js
的文件并填充以下内容。window.markupExtensions = { toHtml: (txt, target) => { const area = document.createElement("textarea"); area.innerHTML = txt; target.innerHTML = area.value; } }
在
wwwroot
下的index.html
中引用它,使用<script src="./markupExtensions.js"></script>
。在
index.razor
中,删除TargetText
引用,并注入 JavaScript 互操作:@inject IJSRuntime JsRuntime
。将段落元素更改为引用:
<p @ref="Target"/>
。更新
@code
以通过互操作调用 JavaScript。string SourceText { get; set; } ElementReference Target; Markdown markdown = new Markdown(); void Convert() { var html = markdown.Transform(SourceText); JsRuntime.InvokeAsync<object>("markupExtensions.toHtml", html, Target); }
运行并展示其优势。解释
Convert
可以是async
,并在必要时 await 响应。在
Shared
下添加一个名为MarkdownHost
的类。using HeyRed.MarkdownSharp; using Microsoft.JSInterop; namespace LibrariesInterop.Shared { public static class MarkdownHost { [JSInvokable] public static string Convert(string src) { return new Markdown().Transform(src); } } }
重新运行应用程序,并从控制台输入。请务必将
LibrariesInterop
更改为您的项目名称。alert(DotNet.invokeMethod("LibrariesInterop", "Convert", "# one\n## two \n* a \n* b"))
解释这也可以使用
Task
来使其异步。
代码隐藏
<g-emoji class="g-emoji" alias="eyes" fallback-src="https://github.githubassets.com/images/icons/emoji/unicode/1f440.png">👀 实时演示
创建一个新的仅客户端项目。
在
Pages
下创建一个名为FetchDataBase
的类(不要与数据库混淆)。public class FetchDataBase : ComponentBase { [Inject] public HttpClient Http { get; set; } public WeatherForecast[] forecasts; protected override async Task OnInitializedAsync() { forecasts = await Http.GetJsonAsync<WeatherForecast[]> ("sample-data/weather.json"); } public class WeatherForecast { public DateTime Date { get; set; } public int TemperatureC { get; set; } public int TemperatureF { get; set; } public string Summary { get; set; } } }
这些是 using 语句。
using Microsoft.AspNetCore.Components; using System; using System.Net.Http; using System.Threading.Tasks;
打开
FetchData.razor
并删除@Inject
行和整个@code
块。在
@page
指令之后添加@inherits FetchDataBase
。运行并显示它正在工作。
MVVM 模式
<g-emoji class="g-emoji" alias="eyes" fallback-src="https://github.githubassets.com/images/icons/emoji/unicode/1f440.png">👀 实时演示
创建一个新的仅客户端项目。
向根目录添加一个名为
MainModel
的类。public class MainModel : INotifyPropertyChanged { public event PropertyChangedEventHandler PropertyChanged; private int _age = 30; public int Age { get => _age; set { if (value != _age) { _age = value; PropertyChanged?.Invoke(value, new PropertyChangedEventArgs(nameof(Age))); } } } public int MaximumHeartRate { get { return 220 - _age; } } public int TargetHeartRate { get { return (int)(0.85*MaximumHeartRate); } } }
添加对
System.ComponentModel
的 using。在
Startup
的ConfigureServices
中注册该类。services.AddSingleton<MainModel>();
在
Shared
下添加Age.razor
。@inject MainModel Model Age: <span style="<span class="pl-c1"><span class="pl-c1">cursor: pointer</span>"</span> @onclick="@(()=>Decrement(true))"> <strong> < </strong> </span> <input type="range" min="13" max="120" @bind-value="Model.Age" @bind-value:event="oninput" /> <span style="<span class="pl-c1"><span class="pl-c1">cursor: pointer</span>"</span> @onclick="@(()=>Decrement(false))"> <strong> > </strong> </span> <span>@Model.Age</span>
添加代码块。
void Decrement(bool decrement) { if (decrement && Model.Age > 13) { Model.Age -= 1; } if (!decrement && Model.Age < 120) { Model.Age += 1; } }
然后在
Shared
下添加HeartRate.razor
。@inject MainModel Model <div> <p>Your target heart rate is: @Model.TargetHeartRate</p> <p>Your maximum heart rate is: @Model.MaximumHeartRate</p> </div>
将新控件添加到
Index.razor
(删除SurveyPrompt
)。<Age/> <HeartRate/>
运行应用程序,并显示心率未更新。
将此
@code
代码添加到HeartRate.razor
的底部。protected override void OnInitialized() { base.OnInitialized(); Model.PropertyChanged += (o, e) => StateHasChanged(); }
重新运行应用程序并显示其正常工作。
解释这可以在更高层面上完成,以自动跨控件传播。
了解更多关于:Blazor 中的 MVVM 支持。
调试
- 在 Chrome 中打开任何应用程序的 URL。
- 显示
SHIFT+ALT+D
按键。 - 如果出现说明,请关闭所有 Chrome 实例(包括系统托盘中的实例),然后粘贴代码以启用调试模式运行。
- 重复按键。
- 显示一个断点,并讨论目前功能非常有限。
总结
👋🏻 Blazor 介绍/概述
<g-emoji class="g-emoji" alias="hocho" fallback-src="https://github.githubassets.com/images/icons/emoji/unicode/1f52a.png">🔪 Razor 组件介绍