具有继承的 Blazor 模板组件

iBe*_*ner 0 c# blazor blazor-component

我有一个基本组件PetTemplate和第二个PetDog继承并使用PetTemplate. PetTemplate有一个名为 的方法ToggleDisplayIndex我的目标是当我单击页面上调用该方法的按钮PetDog.ToggleDisplay并在页面上显示/隐藏 PetDog 详细信息时。

下面示例代码中的“内部”按钮有效,但“外部”按钮无效。如何ToggleDisplay正确从页面或父组件调用该方法?

索引剃刀

@page "/"

<button @onclick="ShowPetDetails">Show Details (Outside)</button>

<PetDog @ref="dog" />

@code {
    PetDog dog;

    void ShowPetDetails()
    {
        dog.ToggleDisplay();
    }
}
Run Code Online (Sandbox Code Playgroud)

宠物狗剃刀

@inherits PetTemplate

<PetTemplate Name="Dog">
    <div>Someone's best friend!</div>
</PetTemplate>
Run Code Online (Sandbox Code Playgroud)

PetTemplate.razor

<div class="mt-3">
    <button @onclick="ToggleDisplay">Show Details (Inside)</button>
    <h3>Pet Name: @Name</h3>
    <div style="display:@display">
        @ChildContent
    </div>
</div>

@code {
    string display = "none";

    [Parameter]
    public string Name { get; set; }

    [Parameter]
    public RenderFragment ChildContent { get; set; }

    public void ToggleDisplay()
    {
        display = display == "none" ? "block" : "none";
        StateHasChanged();
    }
}
Run Code Online (Sandbox Code Playgroud)

Isa*_*aac 5

当你使用

<PetDog @ref="dog" />

@code {
    PetDog dog;

    void ShowPetDetails()
    {
        dog.ToggleDisplay();
    }
}
Run Code Online (Sandbox Code Playgroud)

您实际上创建了对 PetDog 组件的引用,然后尝试在您没有引用的对象(PetTemplate 的实例)上调用派生方法,dog.ToggleDisplay()。为了使其工作,您必须获取对父组件 (PetTemplate) 的引用,并将其提供给派生组件 (PetDog),如下所示:

PetTemplate.razor

<div class="mt-3">
    <button @onclick="ToggleDisplay">Show Details (Inside)</button>
    <h3>Pet Name: @Name</h3>
    <div style="display:@display">
        @ChildContent
    </div>
</div>

@code {
    string display = "none";
    string val;

    [Parameter]
    public string Name { get; set; }

    [Parameter]
    public RenderFragment ChildContent { get; set; }

    public void ToggleDisplay()
    {
        display = display == "none" ? "block" : "none";
       
        InvokeAsync(() => StateHasChanged());
    }
}
Run Code Online (Sandbox Code Playgroud)

宠物狗剃刀

@inherits PetTemplate

<PetTemplate @ref="petTemplate" Name="Dog">
    <div>Someone's best friend!</div>
</PetTemplate>

@code
{
    PetTemplate petTemplate;

    public PetTemplate PetTemplateProp { get; set; }

    protected override void OnAfterRender(bool firstRender)
    {
        if(firstRender)
         {
            PetTemplateProp = petTemplate;
          }
        base.OnAfterRender(firstRender);
    }
}
Run Code Online (Sandbox Code Playgroud)

索引剃刀

@page "/"

<button @onclick="ShowPetDetails">Show Details (Outside)</button>


<PetDog @ref="dog" />

@code {
    PetDog dog;

    void ShowPetDetails()
    {

        dog.PetTemplateProp.ToggleDisplay();
      
    }
}
Run Code Online (Sandbox Code Playgroud)

注意:虽然 Razor 组件是 C# 类,但您不能将它们视为普通类。他们的行为不同。例如,您不能在组件外部定义变量实例并设置其参数等。最好的情况是,您可以捕获对组件的引用并调用组件实例上的公共方法,如当前示例中所做的那样。简而言之,组件对象与普通类不同。

同样重要的是要记住,每个组件都是一个独立的岛,可以独立于其父组件和子组件进行渲染。

但只是想知道如何从继承/使用模板的组件外部更改组件参数值。我尝试了文档或我找到的资源中的方法,但它不适用于我的情况

您不应该(这是一个警告)并且可能不能(现在可能是一个错误)在组件之外更改组件参数的值。例如,您无法捕获对组件的引用并为其参数属性分配值:

<PetTemplate @ref="petTemplate">
    <div>Someone's best friend!</div>
</PetTemplate>

PetTemplate petTemplate; 
Run Code Online (Sandbox Code Playgroud)

这是不允许的:petTemplate.Name="Dog"因为这会更改其组件外部的参数。你只能这样做:

<PetTemplate Name="Dog">
    <div>Someone's best friend!</div>
</PetTemplate>
Run Code Online (Sandbox Code Playgroud)

此外,不推荐从组件本身修改参数属性(当前您应该收到警告,至少这是 Steve Sanderson 向 Blazor 团队建议的)。明确地说,您不应在 PetTemplate 组件中修改参数属性 Name。参数属性应该是自动属性;也就是说,有一个像这样的 get 和 set 访问器:[Parameter] public string Name { get; set; } 并且您不应该像这样使用它:

private string name;

[Parameter]
public string Name 
{ 
  get => name;
  set 
  { 
     if (name != value)
     {
        name = value;

       // Code to a method or whatever to do something
     }
  } 
}
Run Code Online (Sandbox Code Playgroud)

这已被弃用,因为它可能有副作用。组件参数应被视为 DTO,并且不应被修改。如果您希望对参数值执行某些操作,请将其复制到局部变量,然后执行您的操作。