生成首个 Blazor 应用Build your first Blazor app

本文内容

作者:Daniel RothLuke Latham

重要

Blazor WebAssembly 为预览版状态

ASP.NET Core 3.0 支持 Blazor Server。Blazor WebAssembly 在 ASP.NET Core 3.1 中为预览版。

本教程演示如何生成和修改 Blazor 应用。

生成组件Build components

  • 按照 ASP.NET Core Blazor 入门 文章中的指南创建用于本教程的 Blazor 项目。将项目命名为 ToDoList。

  • 在 Pages 文件夹中浏览应用的三个页面:主页、计数器和提取数据。这些页面由 Razor 组件文件(Index.razor、Counter.razor 和 FetchData.razor)实现。

  • 在“计数器”页上,选择“单击我”按钮,在不刷新页面的情况下增加计数器值。增加网页的计数器值通常需要编写 JavaScript。通过 Blazor,可以改为编写 C#。

  • 检查 Counter.razor 文件中 Counter 组件的实现。

Pages/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. }

使用 HTML 定义 Counter组件的 UI。动态呈现逻辑(例如,循环、条件、表达式)是使用名为 Razor 的嵌入式 C# 语法添加的。HTML 标记和 C# 呈现逻辑在构建时转换为组件类。生成的 .NET 类的名称与文件名匹配。

组件类的成员在 @code 块中定义。在 @code 块中,可以指定组件状态(属性、字段)和方法用于处理事件或定义其他组件逻辑。然后,可以将这些成员用作组件呈现逻辑的一部分,并用于处理事件。

选中“单击我”按钮时:

  • 调用 Counter 组件的已注册 onclick 处理程序(IncrementCount 方法)。
  • Counter 组件重新生成其呈现树。
  • 将新的呈现树与前一个呈现树进行比较。
  • 仅应用对文档对象模型 (DOM) 的修改。显示的计数将会更新。
    • 修改 Counter 组件的 C# 逻辑,使计数递增 2 而不是 1。
  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 += 2;
  10. }
  11. }
  • 重新生成并运行应用以查看更改。选择“单击我”按钮。计数器的值将增加 2。

使用组件Use components

使用 HTML 语法将组件加入到另一个组件中。

  • 通过向 Index 组件 (Index.razor) 添加 <Counter /> 元素,将 Counter 组件添加到应用的 Index 组件。

如果在此体验中使用的是 Blazor WebAssembly,则 Index 组件使用 SurveyPrompt 组件。将 <SurveyPrompt> 元素替换为 <Counter /> 元素。如果在此体验中使用的是 Blazor Server 应用,请向 Index 组件添加 <Counter /> 元素:

Pages/Index.razor

  1. @page "/"
  2. <h1>Hello, world!</h1>
  3. Welcome to your new app.
  4. <Counter />
  • 重新生成并运行应用。Index 组件有其自己的计数器。

组件参数Component parameters

组件也可以有参数。组件参数由具有 [Parameter] 的组件类上的公共属性定义。使用这些属性在标记中为组件指定参数。

  • 更新组件的 @code C# 代码,如下所示:

    • 使用 [Parameter] 特性添加公共 IncrementAmount 属性。
    • 增加 currentCount 的值时,更改 IncrementCount 方法以使用 IncrementAmount 属性。
      Pages/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. [Parameter]
  8. public int IncrementAmount { get; set; } = 1;
  9. private void IncrementCount()
  10. {
  11. currentCount += IncrementAmount;
  12. }
  13. }
  • 使用属性在 Index 组件的 <Counter> 元素中指定 IncrementAmount 参数。将计数器递增值设置为 10。

Pages/Index.razor

  1. @page "/"
  2. <h1>Hello, world!</h1>
  3. Welcome to your new app.
  4. <Counter IncrementAmount="10" />
  • 重新加载 Index 组件。每次选择“单击我”按钮时,计数器值递增 10。Counter 组件中的计数器继续递增 1。

路由到组件Route to components

Counter.razor 文件顶部的 @page 指令指定 Counter 组件是路由终结点。Counter 组件处理发送到 /counter 的请求。如果没有 @page 指令,组件将无法处理路由的请求,但该组件仍可以被其他组件使用。

依赖关系注入Dependency injection

Blazor Server 体验 Server experience

如果使用的是 Blazor Server 应用,则 WeatherForecastService 服务在 Startup.ConfigureServices 中注册为单一实例可通过依赖关系注入 (DI) 在整个应用中使用服务的实例:

  1. public void ConfigureServices(IServiceCollection services)
  2. {
  3. services.AddRazorPages();
  4. services.AddServerSideBlazor();
  5. services.AddSingleton<WeatherForecastService>();
  6. }

@inject 指令用于将 WeatherForecastService 服务的实例注入到 FetchData 组件中。

Pages/FetchData.razor

  1. @page "/fetchdata"
  2. @using ToDoList.Data
  3. @inject WeatherForecastService ForecastService

FetchData 组件使用注入的服务(作为 ForecastService)来检索 WeatherForecast 对象的数组:

  1. @code {
  2. private WeatherForecast[] forecasts;
  3. protected override async Task OnInitializedAsync()
  4. {
  5. forecasts = await ForecastService.GetForecastAsync(DateTime.Now);
  6. }
  7. }

Blazor WebAssembly 体验 WebAssembly experience

如果使用的是 Blazor WebAssembly 应用,则注入了 HttpClient,以从 wwwroot/sample-data 文件夹的 weather.json 文件中获取天气预测数据。

Pages/FetchData.razor

  1. @inject HttpClient Http
  2. ...
  3. protected override async Task OnInitializedAsync()
  4. {
  5. forecasts =
  6. await Http.GetJsonAsync<WeatherForecast[]>("sample-data/weather.json");
  7. }

@foreach 循环用于将每个预测实例呈现为“天气”数据表中的一行:

  1. <table class="table">
  2. <thead>
  3. <tr>
  4. <th>Date</th>
  5. <th>Temp. (C)</th>
  6. <th>Temp. (F)</th>
  7. <th>Summary</th>
  8. </tr>
  9. </thead>
  10. <tbody>
  11. @foreach (var forecast in forecasts)
  12. {
  13. <tr>
  14. <td>@forecast.Date.ToShortDateString()</td>
  15. <td>@forecast.TemperatureC</td>
  16. <td>@forecast.TemperatureF</td>
  17. <td>@forecast.Summary</td>
  18. </tr>
  19. }
  20. </tbody>
  21. </table>

生成待办项列表Build a todo list

向应用添加一个实现简单待办事项列表的新组件。

  • 向“页面”文件夹中的应用添加一个新的 Todo Razor 组件。在 Visual Studio 中,右键单击“页面”文件夹,然后选择“添加” > “新项目” > “Razor 组件”。将组件的文件命名为 Todo.razor。在其他开发环境中,将空白文件添加到名为 Todo.razor 的“页面”文件夹中。

  • 为组件提供初始标记:

  1. @page "/todo"
  2. <h3>Todo</h3>
  • Todo 组件添加到导航栏。

NavMenu 组件 (Shared/NavMenu.razor) 用于应用的布局。布局是可以避免应用中出现重复内容的组件。

通过在“Shared/NavMenu.razor”文件中的现有列表项下添加以下列表项标记,为 Todo 组件添加一个 <NavLink> 元素:

  1. <li class="nav-item px-3">
  2. <NavLink class="nav-link" href="todo">
  3. <span class="oi oi-list-rich" aria-hidden="true"></span> Todo
  4. </NavLink>
  5. </li>
  • 重新生成并运行应用。访问新的“待办事项”页面,确认指向 Todo 组件的链接有效。

  • 向项目的根目录添加“TodoItem.cs”文件,以保存一个用于表示待办项的类。为 TodoItem 类使用以下 C# 代码:

  1. public class TodoItem
  2. {
  3. public string Title { get; set; }
  4. public bool IsDone { get; set; }
  5. }
  • 返回到 Todo 组件 (Pages/Todo.razor):

    • @code 块中为待办项添加一个字段。Todo 组件使用此字段来维护待办项列表的状态。
    • 添加无序列表标记和 foreach 循环,以将每个待办项呈现为列表项 (<li>)。
  1. @page "/todo"
  2. <h3>Todo</h3>
  3. <ul>
  4. @foreach (var todo in todos)
  5. {
  6. <li>@todo.Title</li>
  7. }
  8. </ul>
  9. @code {
  10. private IList<TodoItem> todos = new List<TodoItem>();
  11. }
  • 该应用需要 UI 元素来将待办项添加到列表。在未排序列表 (<ul>…</ul>) 下方添加一个文本输入 (<input>) 和一个按钮 (<button>):
  1. @page "/todo"
  2. <h3>Todo</h3>
  3. <ul>
  4. @foreach (var todo in todos)
  5. {
  6. <li>@todo.Title</li>
  7. }
  8. </ul>
  9. <input placeholder="Something todo" />
  10. <button>Add todo</button>
  11. @code {
  12. private IList<TodoItem> todos = new List<TodoItem>();
  13. }
  • 重新生成并运行应用。选择“添加待办项”按钮时没有任何反应,因为没有事件处理程序连接到该按钮。

  • Todo 组件添加 AddTodo 方法,并使用 @onclick 属性注册该方法以选择按钮。选择按钮时,会调用 AddTodo C# 方法:

  1. <input placeholder="Something todo" />
  2. <button @onclick="AddTodo">Add todo</button>
  3. @code {
  4. private IList<TodoItem> todos = new List<TodoItem>();
  5. private void AddTodo()
  6. {
  7. // Todo: Add the todo
  8. }
  9. }
  • 要获得新待办项标题,请在 @code 块顶部添加 newTodo 字符串字段,并使用 <input> 元素中的 bind 属性将其绑定到文本输入的值:
  1. private IList<TodoItem> todos = new List<TodoItem>();
  2. private string newTodo;
  1. <input placeholder="Something todo" @bind="newTodo" />
  • 更新 AddTodo 方法,将具有指定标题的 TodoItem 添加到列表。通过将 newTodo 设置为空字符串来清除文本输入的值:
  1. @page "/todo"
  2. <h3>Todo</h3>
  3. <ul>
  4. @foreach (var todo in todos)
  5. {
  6. <li>@todo.Title</li>
  7. }
  8. </ul>
  9. <input placeholder="Something todo" @bind="newTodo" />
  10. <button @onclick="AddTodo">Add todo</button>
  11. @code {
  12. private IList<TodoItem> todos = new List<TodoItem>();
  13. private string newTodo;
  14. private void AddTodo()
  15. {
  16. if (!string.IsNullOrWhiteSpace(newTodo))
  17. {
  18. todos.Add(new TodoItem { Title = newTodo });
  19. newTodo = string.Empty;
  20. }
  21. }
  22. }
  • 重新生成并运行应用。在待办项列表中添加一些待办项以测试新代码。

  • 每个待办项的标题文本都可以编辑,复选框可以帮助用户跟踪已完成的项。为每个待办项添加一个复选框输入,并将它的值绑定到 IsDone 属性。将 @todo.Title 更改为绑定到 @todo.Title<input> 元素:

  1. <ul>
  2. @foreach (var todo in todos)
  3. {
  4. <li>
  5. <input type="checkbox" @bind="todo.IsDone" />
  6. <input @bind="todo.Title" />
  7. </li>
  8. }
  9. </ul>
  • 若要验证这些值是否已绑定,请更新 <h3> 标头以显示尚未完成的待办项计数(IsDonefalse)。
  1. <h3>Todo (@todos.Count(todo => !todo.IsDone))</h3>
  • 完成的 Todo 组件 (Pages/Todo.razor):
  1. @page "/todo"
  2. <h3>Todo (@todos.Count(todo => !todo.IsDone))</h3>
  3. <ul>
  4. @foreach (var todo in todos)
  5. {
  6. <li>
  7. <input type="checkbox" @bind="todo.IsDone" />
  8. <input @bind="todo.Title" />
  9. </li>
  10. }
  11. </ul>
  12. <input placeholder="Something todo" @bind="newTodo" />
  13. <button @onclick="AddTodo">Add todo</button>
  14. @code {
  15. private IList<TodoItem> todos = new List<TodoItem>();
  16. private string newTodo;
  17. private void AddTodo()
  18. {
  19. if (!string.IsNullOrWhiteSpace(newTodo))
  20. {
  21. todos.Add(new TodoItem { Title = newTodo });
  22. newTodo = string.Empty;
  23. }
  24. }
  25. }
  • 重新生成并运行应用。添加待办项以测试新代码。

创建和使用 ASP.NET Core Razor 组件