【问题标题】:Pass a child component as Parameter in Blazor在 Blazor 中将子组件作为参数传递
【发布时间】:2020-02-28 09:56:45
【问题描述】:

我想在 Blazor 中做一些我通常在 React 中做的事情:创建一个内部使用其他子组件的可重用组件,并能够将这些子组件作为参数传递。我需要能够将子组件视为依赖项,可以根据需要注入不同上下文中可能需要的任何自定义实现。

例如,想象一个TextBox.razor 组件,只要它实现ILabel 接口,它就可以传递自定义组件以根据需要呈现标签。我尝试了类似的方法,但语法似乎无效:

TextBox.razor

从屏幕截图中可以看出,Blazor 不允许我将参数 Label 用作组件。知道如何实现这一目标吗?

【问题讨论】:

  • 你是想传递一个组件实例,还是一个类型?
  • @PeterMorris 一个实例
  • 渲染片段会做你想做的事吗?
  • 不是真的......我想到的是一种组件的“依赖注入”。我使用接口编码,然后我可以决定交换实现。
  • 没有办法做你想做的事。您不能将现有实例移动到 DOM 的另一部分。

标签: dependency-injection blazor asp.net-core-3.0 blazor-server-side blazor-client-side


【解决方案1】:

您应该能够使用模板化组件来完成此操作。

Textbox.razor

@typeparam inputType
<div class="textbox">
    @if(LabelTemplate!=null && TItem!=null)
        @LabelTemplate(TItem)
    <input type="text"/>
</div>


    @code{
        [Parameter]
        public RenderFragment<inputType> LabelTemplate { get; set; }
        [Parameter]
        public inputType TItem { get; set; }
    }

在上面的代码中,您指定组件接受使用@typeparam inputType 的类型,并接收该类型的对象作为参数TItem

您还接受LabelTemplate,它接受inputType 类型的对象。为了渲染这个片段,我们调用@LabelTemplate 并传入我们的TItem 参数。

现在让我们看看如何在名为 PersonForm.razor 的新组件中使用我们的模板化组件

PersonForm.razor

<Textbox TItem="myPerson">
    <LabelTemplate>
        @context.Name
    </LabelTemplate>
</Textbox>
<Textbox TItem="myPerson">
    <LabelTemplate>
        @context.PhoneNumber
    </LabelTemplate>
</Textbox>

@code{

  Person myPerson = new Person { Name = "Jane Doe", PhoneNumber = "999 999 9999" };
    public class Person
    {
        public string Name { get; set; }
        public string PhoneNumber { get; set; }
    }
}

我将我的 Person 对象传递给每个 Textbox 组件的 TItem 属性,并使用 @context 语法在 LabelTemplate 中访问它。

一开始这可能看起来令人困惑,所以请阅读它here

已编辑 这取决于你想要完成什么。 Verbose 语法在组件的“实现”方面带来了灵活性。您不是强制使用可能无法与各种模型/类一起使用的接口,而是让实现指定要做什么。

如果您想要一些不那么冗长/更严格的东西,您也可以执行以下操作。

@implements ILabel 
<div class="textbox"> 
    <label>@Text</label> 
    <input type="text"/> 
</div> 
@code
{ 
    [Parameter] 
    public string Text { get; set; } 
} 

ILabel.cs

    public interface ILabel
    {
        string Text { get; set; }
    }

【讨论】:

  • 我想这是实现类似结果的一种方法,但这并不是我想要的。与仅将组件类型作为参数传递相比,这感觉非常冗长。
  • 也许我误解了你的初衷。查看我的答案的编辑部分
【解决方案2】:

我意识到这可能已经晚了,但我只是挣扎了一下,发现这非常容易!以为我会为寻找的人提供一个简单的答案。

这是我的 OrdersNavigation.razor 文件(我想将其嵌入到标题中):

<div class="nav-strip">
    <NavLink href="orders">
        <Icon Name="@Icons.Cart" /> List
    </NavLink>
    <NavLink href="orders/create">
        <Icon Name="@Icons.Plus" /> Create
    </NavLink>
</div>

现在这是我的PageHeader.razor

<div class="page-header">
    <h3>@Title</h3>
    @Navigation
</h3>
<hr />

@code {
    [Parameter] public string Title { get; set; } = "[TITLE]";
    [Parameter] public RenderFragment Navigation { get; set; }
}

注意 Navigation 属性是一个 RenderFragment - 这是关键。现在在我的页面中,我可以像这样简单地添加它:

<PageHeader Title="Orders">
    <Navigation>
        <OrderNavigation />
    </Navigation>
</PageHeader>

您在这里看到 Title 参数像往常一样输入,但是 Navigation 参数是作为 PageHeader 的元素输入的!真的,你可以在 标签中放任何东西,它会在你有 @Navigation 的地方呈现。

参考:https://blazor-university.com/templating-components-with-renderfragements/passing-data-to-a-renderfragement/

看看你的例子:

Label.razor

<label>@Text</label>

@code {
    [Parameter] public RenderFragment Text { get; set; }
}

TextBox.razor

<div class="textbox">
    <Label>
        <Text>
            <div>
                Embedded label <br />
                You can even drop components in here!
            </div>
        </Text>
    </Label>
    <input  />
</div>

【讨论】:

  • 在您的示例中,您只是渲染作为 RenderFragment 传递的任何组件。在我的示例中,我定义了一个精确的接口ILabel,它作为可以使用什么实现的约束。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2021-01-18
  • 2020-10-06
  • 1970-01-01
  • 2017-10-10
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多