翻译自 Waqas Anwar 2021年3月19日的文章 《A Beginner’s Guide to Blazor Components》 [1]

Blazor 应用程序是组件的组合,这些组件不仅负责呈现用户界面,还协同工作以促进用户交互。它们是 Blazor 应用程序的主要构建块,大多数 Blazor 功能都是围绕组件展开的。在本教程中,我将向您详细介绍组件,并向您展示在 Blazor 应用程序中创建和使用组件的多种技术。

下载源码[2]

Blazor 组件概述

Blazor 组件是 UI 的一个自包含部分,例如一个页面、一个侧边栏菜单、一个联系人表单或仪表盘小工具等。它包括用于呈现 UI 的 HTML 标签和用于处理数据或处理用户事件的 C# 代码。组件可以相互嵌套,也可以在项目中重用,甚至可以跨多个项目重用。Blazor 组件是作为 Razor 组件实现的,这正是它们使用 Razor 语法并具有 .razor 文件扩展名的原因。

为了理解 Blazor 组件的结构及其工作方式,让我们回顾一下 Counter.razor 组件(如果您在 Visual Studio 2019 中使用 Blazor App 模板,它会自动为我们生成)。下面是 Counter.razor 的完整代码。

  1. @page "/counter"
  2. <h1>Counter</h1>
  3. <p>Current count: @currentCount</p>
  4. <button class="btn btn-primary" @onclick="IncrementCount">Click me</button>
  5. @code {
  6. private int currentCount = 0;
  7. private void IncrementCount()
  8. {
  9. currentCount++;
  10. }
  11. }

文件中的第一行使用了 Razor @page 指令来指定组件的路由。这意味着 Counter 组件是页面级或可路由组件,可以在浏览器中使用 URL 末尾的 /counter 路径来访问它。如果我们不指定 @page 指令,则该组件将变为子组件,可以通过将其嵌套在其他组件中来使用它。

  1. @page "/counter"

如下所示,我们还可以声明多个 @page 级别的指令。这将允许我们使用两个 URL 访问组件。

  1. @page "/counter"
  2. @page "/mycounter"

@page 指令之后,是用于指定该组件 UI 的 HTML 标记。这些标记可以使用 Razor 语法动态地使用表达式、条件或循环来渲染 HTML。在上述的 Counter 组件示例中,其 UI 包含一个标题 (h1)、一个段落 (p) 和一个按钮 (button) 元素。段落 (p) 元素使用 Razor 语法来输出 C# 代码块中定义的 currentCount 变量的值。

  1. <p>Current count: @currentCount</p>

按钮 (button) 元素通过调用方法 IncrementCount 来响应用户单击操作,该方法也定义在代码块中。

  1. <button class="btn btn-primary" @onclick="IncrementCount">Click me</button>

最后,是一个代码块,每次调用 IncrementCount 方法时,我们简单地将 currentCount 变量的值加 1。

  1. @code {
  2. private int currentCount = 0;
  3. private void IncrementCount()
  4. {
  5. currentCount++;
  6. }
  7. }

当 Blazor 应用程序进行编译时,HTML 标记和 C# 代码将转换成一个组件类,类名称与组件的文件名相对应。该类的成员是我们在 @code 中定义的相同的变量和方法。允许使用多个 @code 块,所有这些代码块在编译后会合并进同一组件类。

在 Visual Studio 2019 中创建 Blazor 组件

如果您要创建一个页面级组件,请右键单击 Pages 文件夹并选择 添加 > Razor 组件... 菜单选项。

您也可以在解决方案资源管理器中右键单击项目名称,然后使用 Razor 组件 模板创建一个组件。

让我们创建一个文件名为 Calculator.razor 的组件,并添加以下代码。

Calculator.razor

  1. @page "/calculator"
  2. <h3>Calculator</h3>
  3. <div class="form-group">
  4. <label for="number1">Number 1</label>
  5. <input type="number" class="form-control" id="number1" @bind="number1">
  6. </div>
  7. <div class="form-group">
  8. <label for="number2">Number 2</label>
  9. <input type="number" class="form-control" id="number2" @bind="number2">
  10. </div>
  11. <div class="form-group">
  12. <label><b>Total: </b>@total</label>
  13. </div>
  14. <button class="btn btn-primary" @onclick="Calculate">Calculate</button>
  15. @code {
  16. private int number1 = 0;
  17. private int number2 = 0;
  18. private int total = 0;
  19. private void Calculate()
  20. {
  21. total = number1 + number2;
  22. }
  23. }

@code 块具有三个私有变量和一个 Calculate 方法。Calculate 方法简单地将 number1number2 的和赋值给 total 变量。

HTML 标记中有两个输入框,它们使用 @bind 属性来绑定 number1number2 变量:

  1. <input type="number" class="form-control" id="number1" @bind="number1">

变量 total 的值使用 Razor 语法 @total 渲染在页面上:

  1. <label><b>Total: </b>@total</label>

最后,是一个按钮元素,它将 Calculate 方法绑定到 @onclick 事件。每当用户点击按钮时,就会调用 Calculate 方法,页面上的 total 变量的值将更新。

  1. <button class="btn btn-primary" @onclick="Calculate">Calculate</button>

为了轻松访问您的 Calculator 组件,可以通过在 NavMenu.razor 组件中添加以下标记,在应用程序侧边栏中添加 Calculator 组件。

  1. <li class="nav-item px-3">
  2. <NavLink class="nav-link" href="calculator">
  3. <span class="oi oi-calculator" aria-hidden="true"></span> Calculator
  4. </NavLink>
  5. </li>

F5 运行您的应用程序,您应该会看到如下所示的页面。尝试在输入框中输入一些数字,您应该能看到页面上显示的数字之和。点击 Calculate 按钮运行了服务端的 C# 代码,却并没有浏览器回传或页面刷新。一切都感觉那么流畅和快速,就像您在浏览器中使用 JavaScript 进行计算一样。

如果您想检验一下代码是在服务端上运行的,只需尝试在 Calculate 方法中添加一个断点,然后再次按下 F5。这次,当您点击 Calculate 按钮时,您将看到代码执行到断点处停止,您还可以在 tooltips 中看到用户输入,如下图所示:

拆分 Blazor 组件中的标签和代码

如果您创建的是小型组件,那么您可能希望在单个 .razor 文件中编写所有 C# 代码;但如果您有大量的逻辑要写并且为了更好的代码维护,您希望将 C# 代码与 HTML 标签分开,那么可以通过以下两种方式来实现。

使用基类拆分组件

使用这种方式,您可以创建一个独立的类,该类应该从 ComponentBase 类派生。然后,您可以将组件中的属性和方法从 @code 块移动到这个新创建的类,最后,您可以使用 @inherits 指令来指定组件的基类。让我们将这种方式应用于我们上面创建的 Calculator 组件。在项目中创建一个 CalculatorBase 类,并将 C# 代码从 Calculator.razor 移动到这个新类中。

CalculatorBase.cs

  1. public class CalculatorBase : ComponentBase
  2. {
  3. private int number1 = 0;
  4. private int number2 = 0;
  5. private int total = 0;
  6. private void Calculate()
  7. {
  8. total = number1 + number2;
  9. }
  10. }

然后在 Calculator.razor 文件的顶部添加 @inherits 指令,如下:

Calculator.razor

  1. @page "/calculator"
  2. @inherits CalculatorBase
  3. <h3>Calculator</h3>
  4. <div class="form-group">
  5. <label for="number1">Number 1</label>
  6. <input type="number" class="form-control" id="number1" @bind="number1">
  7. </div>
  8. <div class="form-group">
  9. <label for="number2">Number 2</label>
  10. <input type="number" class="form-control" id="number2" @bind="number2">
  11. </div>
  12. <div class="form-group">
  13. <label><b>Total: </b>@total</label>
  14. </div>
  15. <button class="btn btn-primary" @onclick="Calculate">Calculate</button>
  16. @code {
  17. }

此时如果您尝试构建应用程序,则会遇到很多错误抱怨字段和方法的可访问性。

出现上述所有错误的原因是 Calculator 组件继承自 CalculatorBase 类,而我们在 CalculatorBase 类中粘贴的属性和方法是 private。为了确保子组件可以访问这些字段和方法,您需要将它们声明为 public

  1. public class CalculatorBase : ComponentBase
  2. {
  3. public int number1 = 0;
  4. public int number2 = 0;
  5. public int total = 0;
  6. public void Calculate()
  7. {
  8. total = number1 + number2;
  9. }
  10. }

译者注:

基类中的字段和方法改为 protected, 在 .razor 中也是可以的访问的。

CalculatorBase 类必须包含在一个命名空间中,否则会报错。

使用部分类拆分组件

Blazor 组件生成为部分类,这意味着我们可以创建一个与我们的组件同名的 partial 类,并将所有 C# 代码移动到该部分类中。然后,此部分类将成为代码隐藏文件,该文件中声明的字段和属性可在 Blazor 组件中直接使用。让我们创建一个类 Calculator.razor.cs,并将 Calculator 的代码放在这个新类中。

Calculator.razor.cs

  1. public partial class Calculator
  2. {
  3. public int number1 = 0;
  4. public int number2 = 0;
  5. public int total = 0;
  6. public void Calculate()
  7. {
  8. total = number1 + number2;
  9. }
  10. }

如果启用了文件嵌套,您将看到 Visual Studio 会自动将组件和代码隐藏文件显示在一起。

再次运行应用程序,Calculator 会以前面相同的方式工作。

创建和使用子组件

Blazor 子组件是没有 @page 指令的组件。这些组件可以使用标准的 HTML 语法包含在其他组件中。然后,我们可以通过在页面上添加组件来构建复杂的 UI,我们甚至可以在同一个页面上添加同一子组件的多个实例。如果一个子组件可能在多个父组件或页面中重复使用,那么最好将它放在 Shared 文件夹中。让我们在 Shared 文件夹中创建一个简单的 Heading.razor 子组件,并在其中添加以下代码。

Heading.razor

  1. <h3>Calculator</h3>

接下来,将父组件 Calculator.razor 中的 h3 元素替换为 <Heading /> 元素。运行应用程序,您会看到 h3 标题从子组件中渲染到了页面上。

Calculator.razor

  1. @page "/calculator"
  2. @inherits CalculatorBase
  3. <Heading />
  4. <div class="form-group">
  5. <label for="number1">Number 1</label>
  6. <input type="number" class="form-control" id="number1" @bind="number1">
  7. </div>
  8. <div class="form-group">
  9. <label for="number2">Number 2</label>
  10. <input type="number" class="form-control" id="number2" @bind="number2">
  11. </div>
  12. <div class="form-group">
  13. <label><b>Total: </b>@total</label>
  14. </div>
  15. <button class="btn btn-primary" @onclick="Calculate">Calculate</button>

您甚至可以通过复制和粘贴相同的 <Heading /> 元素来添加子组件的多个实例。

  1. <Heading />
  2. <Heading />
  3. <Heading />

现在,如果您运行应用程序,您将会在页面上看到三个 h3 标题。

自定义带参数的 Blazor 组件

只是生成具有相同内容的静态组件不是很有用。如果我们可以将一些数据传递给组件,而不仅仅是自定义它生成的 UI,还自定义其行为或功能,那就更好了。我们可以使用参数来自定义 Blazor 组件。这些参数可以是简单的 intbool 等,也可以是复杂的 CustomerOrder 等。一旦声明了参数,我们便可以使用属性将数据传递给组件。让我们通过在 Heading 组件中声明一个简单的 Title 参数来学习一下这个概念。要指定一个参数,我们要将 [Parameter] 特性附加到一个属性上。

Heading.razor

  1. <h3>@Title</h3>
  2. @code {
  3. [Parameter]
  4. public string Title { get; set; } = "Default Title";
  5. }

我们还为 Title 属性设置了一个默认值 Default Title,当未提供 Title 时,则显示该默认字符串。

Visual Studio 智能感知也可以提示组件参数,因此我们不需要记忆这些参数,这很有用。

我们可以通过传递任意字符串作为 Title 的值来从外部自定义 Title,Heading 组件将自动渲染传递给它的不同字符串。

  1. <Heading Title="Calculator" />

我们还可以使用表达式从父组件到子组件传递数据。让我们创建另外一个子组件 CalculatorTotal.razor,并向其添加以下代码。

CalculatorTotal.razor

  1. <label><b>Total: </b>@Total</label>
  2. @code {
  3. [Parameter]
  4. public int Total { get; set; }
  5. }

现在,您可以使用我们在父 Calculator 控制器中声明和设置的 @total 字段来传递 Total 的值。

Calculator.razor

  1. @page "/calculator"
  2. <Heading Title="Calculator" />
  3. <div class="form-group">
  4. <label for="number1">Number 1</label>
  5. <input type="number" class="form-control" id="number1" @bind="number1">
  6. </div>
  7. <div class="form-group">
  8. <label for="number2">Number 2</label>
  9. <input type="number" class="form-control" id="number2" @bind="number2">
  10. </div>
  11. <div class="form-group">
  12. <CalculatorTotal Total="@total"/>
  13. </div>
  14. <button class="btn btn-primary" @onclick="Calculate">Calculate</button>

将路由参数传递给 Blazor 组件

Blazor 组件还可以接受在 @page 指令中提供的来自路由模板的参数。路由器使用路由参数自动填充相应的组件参数。

让我们看一个如何通过路由将数据传递给组件的示例。创建一个新的名为 MathTable.razor 的 Blazor 组件并添加以下代码。

MathTable.razor

  1. @page "/MathTable/{number:int}"
  2. <h3>Math Table</h3>
  3. <table class="table table-bordered w-25">
  4. @for (int i = 1; i <= 10; i++)
  5. {
  6. <tr>
  7. <td>@Number</td>
  8. <td>x</td>
  9. <td>@i</td>
  10. <td>=</td>
  11. <td>@(Number * i)</td>
  12. </tr>
  13. }
  14. </table>
  15. @code {
  16. [Parameter]
  17. public int Number { get; set; }
  18. }

我们指定了一个带有 int 参数 number 的路由模板:

  1. @page "/MathTable/{number:int}"

该路由参数将自动映射到以下组件参数:

  1. [Parameter]
  2. public int Number { get; set; }

在 HTML 标记中,我使用 number 参数生成一个数学公式表。运行项目并尝试在路由 URL 中传递不同的数字,您将看到根据每一参数值更新的数学公式表。

总结

在本教程中,我介绍了 Blazor 组件的基础知识。我试图用易于理解的示例来演示每个概念,以便您可以快速学习基本概念。 Blazor 组件提供的功能比我在本教程中介绍的要多得多,而且还有许多其他与 Blazor 组件相关的高级主题。在接下来的几周里,我将尝试写更多关于 Blazor 的文章,因此请继续访问我的网站以学习有关 Blazor 的更多知识。

相关阅读:

作者 : Waqas Anwar

翻译 : 技术译站

链接 : 英文原文


  1. https://www.ezzylearning.net/tutorial/a-beginners-guide-to-blazor-components A Beginner’s Guide to Blazor Components

  2. https://github.com/ezzylearning/BlazorComponentsDemo

Blazor 组件入门指南的更多相关文章

  1. Blazor 模板化组件开发指南

    翻译自 Waqas Anwar 2021年4月15日的文章 <A Developer's Guide To Blazor Templated Components> [1] 在我之前的一篇 ...

  2. Blazor 组件库开发指南

    翻译自 Waqas Anwar 2021年5月21日的文章 <A Developer's Guide To Blazor Component Libraries> [1] Blazor 的 ...

  3. Blazor 数据绑定开发指南

    翻译自 Waqas Anwar 2021年3月21日的文章 <A Developer's Guide to Blazor Data Binding> [1] 现如今,大多数 Web 应用程 ...

  4. Blazor 事件处理开发指南

    翻译自 Waqas Anwar 2021年3月25日的文章 <A Developer's Guide To Blazor Event Handling> [1] 如果您正在开发交互式 We ...

  5. Blazor 组件之间使用 EventCallback 进行通信

    翻译自 Waqas Anwar 2021年3月28日的文章 <Communication between Blazor Components using EventCallback> [1 ...

  6. Blazor Server 和 WebAssembly 应用程序入门指南

    翻译自 Waqas Anwar 2021年3月12日的文章 <A Beginner's Guide To Blazor Server and WebAssembly Applications&g ...

  7. Web API 入门指南 - 闲话安全

    Web API入门指南有些朋友回复问了些安全方面的问题,安全方面可以写的东西实在太多了,这里尽量围绕着Web API的安全性来展开,介绍一些安全的基本概念,常见安全隐患.相关的防御技巧以及Web AP ...

  8. Flume NG Getting Started(Flume NG 新手入门指南)

    Flume NG Getting Started(Flume NG 新手入门指南)翻译 新手入门 Flume NG是什么? 有什么改变? 获得Flume NG 从源码构建 配置 flume-ng全局选 ...

  9. ReactJS入门指南

    ReactJS入门指南 本文旨在介绍ReactJS的基本知识,并一步步详细介绍React的基本概念和使用方法等,以及相应的Demo.本文在很大程度上参考了React官方文档和官方指南.如果你英语还不错 ...

随机推荐

  1. iPhone手机怎么和电脑互传文件,一条数据线搞定

    官方的方法是,通过iTunes进行文件的传输.传个文件还要特意安装个iTunes,实在是麻烦. 其实我们只需要在苹果应用商店app store下载Documents这个文件就可以. 另外,Docume ...

  2. 怎样使用yum-cron为CentOS7自动更新重要的安全补丁

    怎样使用yum-cron为CentOS自动更新重要的安全补丁 2017年4月19日 | 分类: [技术] 参考:https://linux.die.net/man/8/yum-cron参考:http: ...

  3. k8s创建资源的两种方式及DaemonSet应用(5)

    一.创建方式分类 Kubernetes 支持两种方式创建资源: (1)用 kubectl 命令直接创建,比如: kubectl run httpd-app --image=reg.yunwei.com ...

  4. mysql基础之视图、事务、索引、外键

    一.视图 视图是一个虚拟表,其内容由查询定义.同真实的表一样,视图包含一系列带有名称的列和行数据.但是,视图并不在数据库中以存储的数据值集形式存在.行和列数据来自由定义视图的查询所引用的表,并且在引用 ...

  5. PTH的几种食用姿势

    PTH PTH(pass the hash)也叫做hash传递.在内网渗透中是一种很经典的攻击方式,原理就是攻击者可以直接通过NTLM Hash(mimikatz或其他手段抓取到的密码hash)访问远 ...

  6. GO语言复合类型05---递归

    package main import ( "fmt" "time" ) /* ·递归就是自己调自己 ·递归一定要有终止条件(否则就是无限死循环) */ /*使 ...

  7. JNDI注入和JNDI注入Bypass

    之前分析了fastjson,jackson,都依赖于JDNI注入,即LDAP/RMI等伪协议 JNDI RMI基础和fastjson低版本的分析:https://www.cnblogs.com/pia ...

  8. THINKPHP_(4)_TP模型中with、withJoin和多层关联的深入分析

    1.个人之前博文: TP模型的多表关联查询和多表字段的关键字搜索 TP6中实现多层关联,第一个表关联第二个表查询出的数据,再关联第三个表 2.withJoin的特性 2.1 第一个特性 在TP模型的多 ...

  9. HarmonyOS系统概述

    HarmonyOS系统概述 系统定位 HarmonyOS是一款"面向未来".面向全场景(移动办公.运动健康.社交通信.媒体娱乐等)的分布式操作系统.在传统的单设备系统能力的基础上, ...

  10. TVM源码框架安装方法

    TVM源码框架安装方法 本文提供如何在各种系统上从零构建和安装TVM包的说明.它包括两个步骤: 首先从C++代码中构建共享库(linux的libtvm.so,macOS的libtvm.dylib和wi ...