首页 > 其他分享 >.NET8 Blazor 从入门到精通:(二)组件

.NET8 Blazor 从入门到精通:(二)组件

时间:2024-08-16 15:18:42浏览次数:11  
标签:void 参数 NET8 组件 Blazor BetterCounter page 路由

目录

Blazor 组件

基础

新建一个项目命名为 MyComponents ,项目模板的交互类型选 Auto ,其它保持默认选项:
image

客户端组件 (Auto/WebAssembly):
最终解决方案里面会有两个项目:服务器端项目客户端项目,组件按存放项目的不同可以分为以下两种组件:

  • 服务器端组件:

    • 主要用于服务器端渲染(SSR)
    • 被放置在服务器端项目中
    • 适用于不需要实时交互或复杂用户交互的场景
  • 客户端组件 (Auto/WebAssembly):

    • 组件位于客户端项目内
    • 使用 WebAssembly 技术进行编译,能够直接与浏览器交互
    • 适合需要交互性和实时更新的应用场景
    • 使用 SignalR 可以实现实时通信,从而增强组件的功能性

两种组件选择原则如下:

  • 如果组件不需要交互性,将其作为服务器端渲染的组件。
  • 如果组件需要交互性(例如响应用户的输入、实时数据更新等),则应该考虑将其作为客户端组件,可以利用 SignalR 提供的实时通信功能。

在客户端项目中新建一个 Demo 组件:

<!-- 选择 Auto 或 WebAssembly ,否则无法交互 -->
@rendermode InteractiveAuto

<h3>Demo</h3>

<!-- 文本不为空时才显示标签 -->
@if (textInfo is not null)
{
    <h4>Info: @textInfo</h4>
}

<!-- 按钮样式参考 Counter 组件 -->
<button class="btn btn-primary" @onclick="UpdateText">Update Text</button>
<!-- 委托方式调用方法,可以传入参数 -->
<button class="btn btn-primary" @onclick="(()=>{UpdateNumber(10);})">Update Number</button>


@code {
    private string? textInfo = null;

    private void UpdateText()
    {
        textInfo = "This is the new information";
    }

    private void UpdateNumber(int i = 0)
    {
        textInfo = $"This is number {i}";
    }
}

在服务器端项目中的 Home 页面中引用 Demo 组件:

@page "/"

<PageTitle>Home</PageTitle>

<h1>Hello, world!</h1>

Welcome to your new app.

<Demo />

在 _Imports.razor 中引用 Demo 组件的命名空间:

@using MyComponents.Client.Pages

路由导航

在客户端项目中添加一个 Start 组件,razor 代码如下:

@*组件可以同时有多个路由*@
@page "/page"
@page "/pages/start"

@*可以使用组件名作路由*@
@attribute [Route(nameof(Start))]

@*页面跳转必须指定交互性,并注入导航管理器*@
@rendermode InteractiveAuto
@inject NavigationManager Navigation

<h3>Start</h3>

@*通过NavigationManager.NavigateTo方法跳转到Counter组件*@
<button class="btn btn-primary" onclick="@(()=>Navigation.NavigateTo(nameof(Counter)))">Go to Counter</button>

@*执行完整的页面重新加载*@
<button class="btn btn-primary" onclick="@(()=>Navigation.Refresh(true))">Refresh</button>
@code {

}

上面的代码演示了如何使用路由和导航管理器进行页面跳转,组件可以同时有多个路由,也可以使用组件名作路由
跳转到其它组件时会用到增强导航,参考 增强的导航和表单处理

参数

组件参数

在客户端项目中添加一个 BetterCounter 组件,razor 代码如下:

@rendermode InteractiveAuto

<h3>BetterCounter</h3>
<p role="status">Current count: @CurrentCount</p>

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

@code {

    //将目标成员表示为组件参数
    [Parameter]
    public int CurrentCount { get; set; }

    private void IncrementCount()
    {
        CurrentCount++;
    }
}

组件参数将数据传递给组件,使用组件类中包含 [Parameter] 特性的公共 C# 属性进行定义,参考组件参数单向绑定

使用组件时需要将目标成员作为组件参数传递给组件,如在 Home 页面中引用 BetterCounter 组件:

<BetterCounter CurrentCount="100" />
<!-- 或 -->
<BetterCounter CurrentCount=@currentCount />

路由参数

路由器使用路由参数以相同的名称填充相应的组件参数,路由参数名不区分大小写,参考文档 路由参数

在 BetterCounter 组件的 razor 代码中添加如下路由:

@*路由参数(无约束)*@
@page "/BetterCounter/{CurrentCount}"

@*路由参数约束*@
@page "/BetterCounter/{CurrentCount:int}"

@*可选路由参数(与上面任意一个路由搭配使用实现可选效果)*@
@page "/BetterCounter"

为了实现可选路由参数,需要在组件中添加一个默认值:

//将目标成员表示为组件参数
//需要将参数属性的类型更改为可为 null,这样就可以分辨出它是否被指定了值
[Parameter]
public int? CurrentCount { get; set; }

//为可选参数指定默认值    
protected override void OnInitialized()
{
    base.OnInitialized();    
    CurrentCount = CurrentCount ?? 1;
}

添加一个 Titlet 成员来接受查询字符串的参数:


//指定组件参数来自查询字符串
//路由:/BetterCounter?Titlet=asd
[SupplyParameterFromQuery]
public string? Titlet { get; set; } = "BetterCounter";
  • 路由参数:在添加组件的 @page 声明时,通过将路由参数的名称括在一对 { 大括号 } 中,在URL中定义了路由参数,参考示例 路由参数

  • 路由参数约束:以冒号为后缀,然后是约束类型,约束类型参考文档 路由约束。以路由 /BetterCounter/abs 为例:

    • 没有路由约束时会报类型转换异常(字符串无法转为int类型)
    • 有路由约束时会显示404错误(没有匹配到该 URL)
  • 可选路由参数:Blazor不明确支持可选路由参数,但通过在组件上添加多个 @page 声明,可以轻松实现等效的路由参数,参考文章 可选路由参数

  • 查询字符串:使用 [SupplyParameterFromQuery] 属性指定组件参数来自查询字符串,更多应用场景参考文档 查询字符串

生命周期事件

以下简化图展示了 Razor 组件生命周期事件处理,参考文档 生命周期事件

image

在 Counter 组件中添加日志记录,观察组件的生命周期:

@inject ILogger<Counter> log

//...

@code {
    //...
    protected override void OnInitialized()
    {
        log.LogInformation($"Initialized at {DateTime.Now}");
    }
    protected override void OnParametersSet()
    {
        log.LogInformation($"ParametersSet at {DateTime.Now}");
    }
    protected override void OnAfterRender(bool firstRender)
    {
        log.LogInformation("OnAfterRender: firstRender = {FirstRender}", firstRender);
    }
}
  • 组件初始化 (OnInitialized{Async}) :专门用于在组件实例的整个生命周期内初始化组件,参数值和参数值更改不应影响在这些方法中执行的初始化。

  • 设置参数之后 (OnParametersSet{Async}):在 OnInitialized 或 OnInitializedAsync 中初始化组件后或父组件重新呈现并变更参数时调用。

  • 组件呈现之后 (OnAfterRender{Async}):OnAfterRender 和 OnAfterRenderAsync 组件以交互方式呈现,并在 UI 已完成更新(例如,元素添加到浏览器 DOM 之后)后调用。OnAfterRender 和 OnAfterRenderAsync 的 firstRender 参数:

    • 在第一次呈现组件实例时设置为 true。
    • 可用于确保初始化操作仅执行一次。

运行后导航到Counter界面,控制台输出如下:
image

状态更改

StateHasChanged 通知组件其状态已更改。 如果适用,调用 StateHasChanged 会导致组件重新呈现

将自动为 EventCallback 方法调用 StateHasChanged,也可以根据实际需求在组件中手动调用 StateHasChanged:

private async void IncrementCount()
{
    currentCount++;
    await Task.Delay(1000);
    StateHasChanged();

    currentCount++;
    await Task.Delay(1000);
    StateHasChanged();

    currentCount++;
    await Task.Delay(1000);
    StateHasChanged();
}

上面的代码,如果不调用 StateHasChanged 则点击后只会显示 1 ,用 StateHasChanged 后则会依次显示 1 2 3 。

组件事件

嵌套组件的常见方案是在发生子组件事件时在父组件中执行某个方法(如子组件中的 onclick 事件),跨组件公开事件请使用 EventCallback ,父组件可向子组件的 EventCallback 分配回调方法。

在 Counter 组件中添加一个事件:

@code {
    private int currentCount = 0;

    //定义一个事件回调参数
    [Parameter]
    public EventCallback<int> OnCounterChange { get; set; }

    private async Task IncrementCount()
    {
        currentCount++;
        //触发事件回调
        await OnCounterChange.InvokeAsync(currentCount); 
    }
}

在另一个客户端组件为 Counter 组件的事件分配回调方法(服务端组件会报错):

<Counter OnCounterChange="UpdateCounter" />

@code {
    private int currentCount = 0;
    private void UpdateCounter(int val)
    {
        currentCount = val;
    }
}

标签:void,参数,NET8,组件,Blazor,BetterCounter,page,路由
From: https://www.cnblogs.com/timefiles/p/18362903

相关文章

  • ArkTs基础语法-声明式UI-页面和自定义组件生命周期
    页面和自定义组件生命周期组件和页面的关系生命周期页面生命周期组件生命周期普通流程为:其他流程:自定义组件的创建和渲染流程首次创建重新渲染自定义组件的删除自定义组件监听页面生命周期组件和页面的关系自定义组件:@Component装饰的UI单元,可以组合多个系统组件......
  • 一款开箱即用的整合第三方登录的开源组件,整合了国内外数十家知名平台的OAuth登录(附源
    前言在现代应用开发中,第三方登录认证是一个不可或缺的功能,它为用户带来了便捷的登录体验。然而,开发者在实现这一功能时往往会遇到一些痛点:需要对接多个第三方平台的SDK,每增加一个平台就要编写一套新的代码,导致代码维护变得复杂且困难。此外,从头开发一个完整的登录功能不仅需要......
  • 界面控件DevExpress .NET MAUI v24.1 - 发布TreeView等新组件
    DevExpress拥有.NET开发需要的所有平台控件,包含600多个UI控件、报表平台、DevExpressDashboardeXpressApp框架、适用于VisualStudio的CodeRush等一系列辅助工具。屡获大奖的软件开发平台DevExpress今年第一个重要版本v23.1正式发布,该版本拥有众多新产品和数十个具有高影响力......
  • 在vue中封装第三方组件的标准
    在Vue.js项目中,经常会用到各种第三方组件库来提升开发效率和用户体验。然而,直接使用这些组件可能会导致代码结构混乱、样式冲突等问题。为了保持项目的整洁和可维护性,我们需要优雅地封装这些第三方组件。下面是一篇关于如何在Vue中优雅地封装第三方组件的文章。如何在Vue中优......
  • 12 Text 组件
    12Text组件Tkinter是Python的标准GUI库,而Text组件是其中用于显示和编辑多行文本的控件。以下是对Text组件的详细说明和一个使用案例。Text组件属性基本属性width:文本框的宽度,通常以字符数为单位。height:文本框的高度,以行数为单位。wrap:指定文本换行的......
  • 13 Listbox 组件
    13Listbox组件Tkinter的Listbox组件是一个用于显示列表项的控件,用户可以从中选择一个或多个项目。以下是对Listbox组件的详细说明和一个使用案例。Listbox组件属性基本属性width:控件的宽度,通常以字符数为单位。height:控件的高度,以行数为单位。选择模式sel......
  • 在 Vue 自定义事件中,父组件如何接收子组件传递的多个参数?
    在Vue中,自定义事件是父组件和子组件之间通信的重要方式。父组件可以监听子组件的事件,子组件则通过触发自定义事件将数据传递给父组件。如果子组件需要向父组件传递多个参数。 $emit 方法使用一、场景介绍假设我们有一个父组件和一个子组件。子组件需要通过自定义事件向父组......
  • ofcommon.dll故障深度探索:Office组件恢复的高级策略揭秘
    解决ofcommon.dll丢失的问题,采取以下专业步骤可以帮助您恢复Office组件的正常运作:1.系统文件检查:•以管理员身份运行命令提示符,输入sfc/scannow并回车。这将扫描并修复系统文件,包括可能缺失的ofcommon.dll。2.Office修复:•打开“控制面板”>“程序”>“程序和功......
  • 增量生成器简化BlazorServer兼容BlazorAuto模式
    本文简略介绍一下如何使用增量生成器(IncrementalGenerator)简化BlazorServer兼容Auto模式比如现在有一个BlazorServer项目的Razor页面//UserIndex.razor@code{[Inject,NotNull]IUserService?Service{get;set;}}如果IUserService的实现不支持运行在WebAssemb......
  • vue 组件调用组件自身,递归调用组件自身
    父组件<template><divclass="page-box"><!--<child><templatev-slot:default="scope"><div>slot</div><div>{{scope.data1}}</div>......