在Blazor中添加动态组件列表

6

我刚开始学习Blazor(v0.3),并进行了一些测试。我想使用Blazor添加一个列表。

首先,我创建了一个List<string>来测试在同一页上显示一个简单的列表。

<ul>
    @foreach (var item in listItems)
    {
        <li>@item</li>
    }
</ul>


@functions {

    private List<string> listItems = new List<string>();
    private string newItem;

    private void AddItem()
    {
        if (string.IsNullOrEmpty(newItem))
            return;

        listItems.Add(newItem);
        newItem = "";
    }

}

这个现在运作得很好,每当我添加一个元素时就会将其添加到列表中。但是,当我尝试添加组件时,添加单个组件很容易,基于这个问题 这里, 但对于列表,我遇到了下一个问题:

  • 我创建了一个<li>组件,用于测试组件的功能性,以下是该组件的视图
<li id="@ID">
    @Text
</li>   




@functions {
  [Parameter]
  string Text { get; set; } 
  [Parameter]
  string ID { get; set; }
}
  • 然后在父视图中执行
<input type="text" bind="TxtExample" name="inpAdd"/>
  <button onclick="@addCompoment">add comp1</button>
<div class="simple-list-list">
    @if (!componentListTest.Any())
    {
        <p>You have no items in your list</p>
    }
    else
    {
        <ul>
            @foreach (var item in componentListTest)
            {
                @item
            }
        </ul>
    }
</div>

@functions {

    private List<RenderFragment> componentListTest { get; set; }
    private int currentCount {get; set;}
    private string TxtExample { get; set; }

    protected override void OnInit()
    {
        currentCount = 0;
        componentListTest = new List<RenderFragment>();
    }


    protected void addCompoment()
    {

        componentListTest.Add(CreateDynamicComponent(currentCount));
        currentCount++;
    }


    RenderFragment CreateDynamicComponent(int counter) => builder =>
    {
        var seq = 0;
        builder.OpenComponent(seq, typeof(listExample));
        builder.AddAttribute(++seq, "Text", "text --  "+TxtExample);
        builder.AddAttribute(++seq, "id","listed-"+counter);

        builder.CloseComponent();

    };
}

当我加载第一个元素时,它被正确地加载了: enter image description here 但是当我进入第二个元素时,所有元素都被替换为最后一个元素: enter image description here 有什么想法是怎么回事?

我建议使用最新版本,目前是0.3。 - Flores
yup 是 0.3 而不是 0.2。 - TiGreX
2个回答

5
你把它想得太复杂了。为使这种情况正常工作,你不需要动态实例化组件。
你只需执行以下操作:
<ul>
    @foreach (var item in listItems)
    {
        <myComponent bind-myVar="@item"></myComponent>
    }
</ul>

组件将为您实例化。
还可以在这里查看如何使参数在您的组件上工作。

我的问题不在于制作列表,而是动态加载组件。顺便我会查看一下那个链接。 - TiGreX
1
我的观点是,在99%的情况下,您不需要通过编程方式实例化。 - Flores
1
哈哈,我已经寻找答案一段时间了,完全忘记了这是添加动态内容的正确方式。谢谢你提醒我。我想对于我们中的一些人来说,摆脱向DOM添加内容的旧思维模式可能需要一段时间。 - George Harnwell
2
如果列表中的所有对象都是相同类型,那么对于他的使用情况来说,这可能是一个不错的选择。但如果你的列表由多态对象组成,则不是一个好的选择。假设他有一个水果类型的集合。该列表可以包含香蕉、苹果和橙子,它们都是水果类型的后代。假设它们将被呈现为不同的形式。仅使用参数会失去封装和关注点分离的所有好处,因为封闭组件需要知道如何呈现每种水果。此外,添加另一种类型也将需要更改封闭组件。 - ATL_DEV

0
这是因为TxtExample是组件的全局变量。当Blazor检测到潜在的UI更改时,它会重新计算整个组件并更新DOM中的任何差异。因此,当您更改文本框时,TxtExample会被更新,然后Razor会重新计算,将TxtExample的新值插入所有行中。

我知道你的意思,但在第一个例子中,List<string> @newItem 也是组件的全局变量。但是当我添加一个项目时,所有旧项目保留了它们的值。有什么想法吗? - TiGreX
1
我有点困惑 CreateDynamicComponent lambda 是如何工作的,比如 builder 是从哪里来的,或者 listExample 是什么,但我猜测 RenderFragment 每次都会重新计算,而 newItem 不会,因为它是值类型。尝试创建一个字符串列表,表示所有 TxtExample 条目,以便可以循环遍历并显示每个条目。 - Dan Friedman

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接