65.9K
CodeProject 正在变化。 阅读更多。
Home

Blazor 和 WebAssembly

starIconstarIconstarIconstarIconstarIcon

5.00/5 (3投票s)

2019 年 11 月 20 日

MIT

5分钟阅读

viewsIcon

27337

Blazor 和 WebAssembly 示例(Blazor 演示文稿的一部分)

Build Status

Release Status

免费 Azure 账户 获取您的 免费 Azure 账户

此存储库包含使用 Blazor 的 WebAssembly,在浏览器中使用 C# 和 .NET 的演示示例。

Blazor 入门

👋🏻 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

https://:8080/primes.html

打开控制台,显示 JavaScript 与 WebAssembly 的时间对比。

入门

创建一个新的带有 .NET Core 托管的 Blazor 项目。运行应用程序并逐步浏览各个选项卡。

  1. 注意,返回时计数器会重置为零。
  2. 显示 Shared 项目定义了一个在客户端和服务器之间共享的 WeatherForecast 类。
  3. 演示 Startup 中的服务注册。
  4. 在客户端上打开 Startup 以配置类似的服务。
  5. 逐步讲解 Counter.razor 的逻辑。
  6. 指出 FetchData.razor 使用 HttpClient,但它已注入以获得正确的配置。
  7. 在浏览器中激活网络调试。刷新并显示正在加载的 DLL。

可重用组件

<g-emoji class="g-emoji" alias="eyes" fallback-src="https://github.githubassets.com/images/icons/emoji/unicode/1f440.png">👀 实时演示

创建一个新的 Blazor 项目(无托管,仅客户端)。

  1. Shared 下创建一个 Razor 视图组件,并将其命名为 LabelSlider.razor

  2. 粘贴以下 HTML。

    <input type="range" min="@Min" max="@Max" @bind="@CurrentValue" />
    <span>@CurrentValue</span>
  3. @code 块中添加。

    [Parameter]
    public int Min { get; set; }
    
    [Parameter]
    public int Max { get; set; }
    
    [Parameter]
    public int CurrentValue { get; set; }
    
  4. 将其添加到 Counter 页面。

    <LabelSlider Min="0" Max="99" CurrentValue="@currentCount"/>
  5. 展示单击如何更新滑块,但滑动不会更新宿主页面。还要注意,值仅在您停止滑动时更新,并且仅在滑块上更新,而不是在“当前计数”上更新(尽管单击按钮会更新滑块,反之则不然)。

  6. LabelSlider 中,将绑定更改为 @bind-value="@CurrentValue",然后添加额外的 @bind-value:event="oninput" 以在滑动时刷新。

  7. 添加一个用于当前值更改的事件并实现它(这将替换现有的 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; }
    
  8. Counter.razor 中将绑定更新为 @bind-CurrentValue

  9. 运行并显示它正在获取值,但没有刷新。解释我们稍后将介绍手动 UI 刷新。

库和互操作

<g-emoji class="g-emoji" alias="eyes" fallback-src="https://github.githubassets.com/images/icons/emoji/unicode/1f440.png">👀 实时演示

创建一个新的仅客户端项目。

  1. 在 NuGet 包中,搜索并安装 Markdown,请访问 此处

  2. 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>
  3. 在顶部添加 @using HeyRed.MarkdownSharp

  4. 添加一个 @code 块。

    string SourceText { get; set; }
    string TargetText { get; set; }
    Markdown markdown = new Markdown();
    
    void Convert()
    {
        TargetText = markdown.Transform(SourceText);
    }
  5. 运行并展示转换。解释绑定是“安全的”,不会展开 HTML。

  6. wwwroot 下创建一个名为 markupExtensions.js 的文件并填充以下内容。

    window.markupExtensions = {
        toHtml: (txt, target) => {
            const area = document.createElement("textarea");
            area.innerHTML = txt;
            target.innerHTML = area.value;
        }
    }
  7. wwwroot 下的 index.html 中引用它,使用 <script src="./markupExtensions.js"></script>

  8. index.razor 中,删除 TargetText 引用,并注入 JavaScript 互操作:@inject IJSRuntime JsRuntime

  9. 将段落元素更改为引用:<p @ref="Target"/>

  10. 更新 @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);
    }
  11. 运行并展示其优势。解释 Convert 可以是 async,并在必要时 await 响应。

  12. 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);
            }
        }
    }
  13. 重新运行应用程序,并从控制台输入。请务必将 LibrariesInterop 更改为您的项目名称。

    alert(DotNet.invokeMethod("LibrariesInterop", "Convert", "# one\n## two \n* a \n* b"))
  14. 解释这也可以使用 Task 来使其异步。

代码隐藏

<g-emoji class="g-emoji" alias="eyes" fallback-src="https://github.githubassets.com/images/icons/emoji/unicode/1f440.png">👀 实时演示

创建一个新的仅客户端项目。

  1. 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;
  2. 打开 FetchData.razor 并删除 @Inject 行和整个 @code 块。

  3. @page 指令之后添加 @inherits FetchDataBase

  4. 运行并显示它正在工作。

MVVM 模式

<g-emoji class="g-emoji" alias="eyes" fallback-src="https://github.githubassets.com/images/icons/emoji/unicode/1f440.png">👀 实时演示

创建一个新的仅客户端项目。

  1. 向根目录添加一个名为 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。

  2. StartupConfigureServices 中注册该类。

    services.AddSingleton<MainModel>();

  3. 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>&nbsp;&lt;&nbsp;</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>&nbsp;&gt;&nbsp;</strong>
    </span>
    <span>@Model.Age</span>
  4. 添加代码块。

    void Decrement(bool decrement)
    {
        if (decrement && Model.Age > 13)
        {
            Model.Age -= 1;
        }
        if (!decrement && Model.Age < 120)
        {
            Model.Age += 1;
        }
    }
  5. 然后在 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>
  6. 将新控件添加到 Index.razor(删除 SurveyPrompt)。

    <Age/>
    <HeartRate/>
  7. 运行应用程序,并显示心率未更新。

  8. 将此 @code 代码添加到 HeartRate.razor 的底部。

    protected override void OnInitialized()
    {
        base.OnInitialized();
        Model.PropertyChanged += (o, e) => StateHasChanged();
    }
  9. 重新运行应用程序并显示其正常工作。

  10. 解释这可以在更高层面上完成,以自动跨控件传播。

了解更多关于:Blazor 中的 MVVM 支持

调试

  1. 在 Chrome 中打开任何应用程序的 URL。
  2. 显示 SHIFT+ALT+D 按键。
  3. 如果出现说明,请关闭所有 Chrome 实例(包括系统托盘中的实例),然后粘贴代码以启用调试模式运行。
  4. 重复按键。
  5. 显示一个断点,并讨论目前功能非常有限。

总结

Blazor 入门

👋🏻 Blazor 介绍/概述

<g-emoji class="g-emoji" alias="hocho" fallback-src="https://github.githubassets.com/images/icons/emoji/unicode/1f52a.png">🔪 Razor 组件介绍

© . All rights reserved.