在Blazor中将子组件作为参数传递

时间:2019-11-02 11:05:09

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

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

例如,假设有一个TextBox.razor组件,它使您能够传递自定义组件以根据需要呈现标签,只要它实现了ILabel接口即可。我尝试过类似的操作,但是语法似乎无效:

TextBox.razor

enter image description here

从屏幕截图中可以看到,Blazor不允许我使用参数Label作为组件。关于如何实现这一目标的任何想法?

2 个答案:

答案 0 :(得分:1)

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

这是我的 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>

答案 1 :(得分:0)

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

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

已编辑 这仅取决于您要完成什么。详细语法带来了组件“实施”方面的灵活性。您可以让实现指定执行操作,而不是强制使用可能不适用于多种模型/类的接口。

如果您想要一些不太冗长/更僵化的内容,也可以执行以下操作。

@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; }
    }