.net 为Blazor组件传递多个不同的HTML参数-自定义列表/表格组件

6mzjoqzu  于 2022-11-26  发布在  .NET
关注(0)|答案(3)|浏览(271)

我想创建一个自定义的ListView,用一些通用的东西(和一些逻辑来禁用它们) Package 子级。但是,子级的内容是未知的,每个子级都是不同的,并且由父级管理。
输入(例如,来自Index.razor,分量为MyList.razor):

<!-- Other code -->

<MyList>
    <Child Title="Paragraph">
        <p>May have any HTML content</p>
    </Child>
    <Child Title="Link">
        <a href="://example.com">Example Link</a>
    </Child>
    <Child Title="Custom HTML">
        <div>Could be anything in here</div>
        <button onclick="this.OnButtonClicked">Click Me</button>
    </Child>
</MyList>

结果:

<div class="list">
    <div class="child">
        <p>Row 1: Paragraph @*Title here*@</p>

        <div class="row-content"> @*HTML content here*@
            <p>May have any HTML content</p>
        </div>
    </div>
    <div class="child">
        <p>Row 2: Link @*Title here*@</p>

        <div class="row-content"> @*HTML content here*@
            <a href="://example.com">Example Link</a>
        </div>
    </div>
    <!-- More -->
</div>

我试过templated components,但是模板对所有的孩子都是固定的。Dynamically-rendered ASP.NET Core Razor components会要求我为每个孩子创建一个组件类,这不是很理想。有什么解决方案吗?
这是我迄今为止最好的尝试,但我不知道如何将RenderFragment传递给孩子:
第一次
我不知道如何在Index.razor中使用它:

<AppBoard>
    <!-- What's here? -->
</AppBoard>
sczxawaw

sczxawaw1#

您应该能够使用简单的“子内容”组件来完成此操作。

我的清单

<div class="list bg-secondary p-2">
    @ChildContent
</div>

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

我的子列表

<div class="child bg-dark text-white p-2 m-3">
    <p>Row @(this.Row): @this.Title </p>
    <div class="row-content">
        @ChildContent
    </div>
</div>

@code {
    [Parameter] public RenderFragment? ChildContent { get; set; }
    [Parameter, EditorRequired] public string Title { get; set; } = "No title Provided";
    [Parameter, EditorRequired] public int Row { get; set; }
}

然后道:

@page "/"

<PageTitle>Index</PageTitle>

<h1>Hello, world!</h1>

Welcome to your new app.

<SurveyPrompt Title="How is Blazor working for you?" />

<MyList>
    <MyListChild Row=1 Title="Paragraph">
        <p>May have any HTML content</p>
    </MyListChild>
    <MyListChild Row=2 Title="Link">
        <a href="http://example.com">Example Link</a>
    </MyListChild>
    <MyListChild Row=3 Title="Custom HTML">
        <div>The last time this button was clicked is @Message</div>
        <button class="btn btn-primary" @onclick="this.OnButtonClicked">Click Me</button>
    </MyListChild>
</MyList>

@code {
    private string Message = DateTime.Now.ToLongTimeString();

    private void OnButtonClicked()
        => this.Message = DateTime.Now.ToLongTimeString();
}

我在这里使用手动编号是因为,虽然你可以在MyList中创建一个系统,它级联一个对象来自动获得编号,但你并不控制呈现过程。不能保证子组件将按照标记中的顺序被创建或呈现。所以我“保持简单”。
我添加了一些额外的CSS,以便您可以更好地查看结果:

cvxl0en2

cvxl0en22#

如何将RenderFragments传递给子级:
为了将父组件提供的内容插入子组件中,使用了一个名为Render Fragment的特性。下面举一个例子来解释它的细节。
首先创建一个父组件,如下所示:

@page "/ParentComponent"

<h1 class="text-danger">Parent Child Component</h1>

<ChildComponent Title="This title is passed as a parameter from the Parent Component">
    A `Render Fragment` from the parent!
</ChildComponent>

<ChildComponent Title="This is the second child component"></ChildComponent>

@code {

}

现在,子组件为:

<div>
    <div class="alert alert-info">@Title</div>
    <div class="alert alert-success">
        @if (ChildContent == null)
        {
            <span> Hello, from Empty Render Fragment </span>
        }
        else
        {
            <span>@ChildContent</span>
        }
    </div>
</div>

@code {
    [Parameter]
    public string Title { get; set; }

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

Title公共属性由Parameter属性修饰,它允许包含ChildComponent得组件设置特定得值.
这里还定义了另一个公共参数,这次是特殊得RenderFragment类型,可以访问ChildComponent得标签中父组件设置得内容,如果父组件没有设置该内容,比如第二次将ChildComponent放到页面上时,可以通过检查是否为null来显示默认内容。
我认为代码的问题在于必须将参数定义为RenderFragment

ix0qys7i

ix0qys7i3#

使用参数RenderFragment<T>呈现Fragment。这为子级提供了类型T的上下文。
父组件:(添加您自己的html等)。我在这里使用TItem来阐明它的用途。

@typeparam TItem

@foreach(var item in Data)
{
    @ChildContent(item)
}

@code {
    [Parameter, EditorRequired]
    public RenderFragment<TItem> ChildContent { get; set; } = default!;

    [Parameter, EditorRequired]
    public IEnumerable<TItem> Data { get; set; } = default!;
}

这将遍历列表并为ChildContent提供类型为TITem的context

注意:renderfragment是一个委托。当您使用<T>时,这表示该委托具有一个默认为T类型的参数,称为context

每个子组件都需要有自己的

[Parameter, EditorRequired]
public Renderframent ChildContent { get; set;}

用法

<ParentComponent Data=myList >
    <ChildComponent1 Title="Paragraph">
        <p>May have any HTML content</p>
    </ChildComponent1>
</ParentComponent>

@code {
    private List<ListItem> myList;
}

ParentComponent内的任何地方,您都可以将当前项引用为context。例如,如果您的项具有Name属性,则可以使用context.Name
在这种情况下,您的ChildComponent不知道TITem,但是context将在组成组件的标记区域中可用。

您可以在这里做的聪明事:

子组件可以传入TITem:

@typeparam TItem

@ChildContent(Item)

@code {
    [Parameter, EditorRequired]
    public RenderFragment<TItem> ChildContent { get; set; } = default!;

    [Parameter, EditorRequired]
    public TItem Item { get; set; } = default!;
}

用法

<ParentComponent Data=myList >
    <ChildComponent1 Title="Paragraph" Item=context>
        <p>May have any HTML content</p>
    </ChildComponent1>
    @context
</ParentComponent>

这会带来一个小问题,尽管您将有一个嵌套的上下文。要解决这个问题,您需要重命名至少一个上下文以使其唯一。

<ParentComponent Data=myList Context="parentContext" >
    <ChildComponent1 Title="Paragraph" Item=parentContext>
        @context.Name       //
        @parentContext.Name // Both valid here
        <p>May have any HTML content</p>
    </ChildComponent1>
    @parentContext.Name
</ParentComponent>

相关问题