You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Blazor项目:如何创建可动态生成列表项的有序列表组件

问题

我正在开发Blazor项目,想要创建一个可动态生成<li>并展示数据的OrderedList组件。具体需求:

  • 获取子组件ListItem的参数,循环提取属性值在<ul>中展示内容
  • 为每个ListItem生成带属性名的列表头部
  • 支持两种ListItem:一种绑定数据属性展示值,一种自定义内容(比如操作按钮)

已尝试实现但无法正确获取ListItem的参数,请求指导和代码示例。

当前尝试的代码:

<!-- 使用示例 -->
<OrderedList Items="pagedResult.Items">
    <ListItem Header="Name" Property="Name" />
    <ListItem Header="Actions">
        <button type="button">
            Edit
        </button>
    </ListItem>
</OrderedList> 

<!-- OrderedList.razor 当前实现 -->
<ul>
@foreach (var item in Items)
        {
            <li>
                @foreach (var listItem in ListItems)
                {
                    <span>
                        @item.GetType().GetProperty(listItem.Property).GetValue(item)
                    </span>
                }
            </li>
        }
</ul>

@code {
    [Parameter] public List<OrganizationResponse> Items { get; set; }
    [Parameter] public RenderFragment ListItems { get; set; }
}

<!-- ListItem.razor 当前实现 -->
<div>
    @ChildContent
</div>

@code {
    [Parameter] public string Header { get; set; }
    [Parameter] public string Property { get; set; }
    [Parameter] public bool Sortable { get; set; }
    [Parameter] public RenderFragment ChildContent { get; set; }
}
解决方案

核心问题是无法通过RenderFragment直接获取ListItem的参数,需要通过级联参数让子组件主动注册到父组件,同时将OrderedList改为泛型组件提升通用性。

1. 修改ListItem.razor,添加级联参数注册到父组件

@if (ChildContent != null)
{
    @ChildContent
}

@code {
    // 级联获取父组件引用
    [CascadingParameter] private OrderedList<TItem> ParentList { get; set; }

    [Parameter] public string Header { get; set; }
    [Parameter] public string Property { get; set; }
    [Parameter] public bool Sortable { get; set; }
    [Parameter] public RenderFragment<TItem> ChildContent { get; set; } // 改为带数据上下文的RenderFragment

    protected override void OnInitialized()
    {
        ParentList?.AddListItem(this);
    }
}

2. 重写OrderedList.razor,实现表头渲染和动态行内容

<div class="ordered-list-container">
    <!-- 列表头部 -->
    <div class="list-header">
        @foreach (var listItem in _registeredItems)
        {
            <span class="header-cell">
                @listItem.Header
                @if (listItem.Sortable)
                {
                    <span> ↑</span> <!-- 可添加排序图标 -->
                }
            </span>
        }
    </div>

    <!-- 列表主体 -->
    <ul class="list-body">
        @foreach (var item in Items)
        {
            <li class="list-row">
                @foreach (var listItem in _registeredItems)
                {
                    <span class="row-cell">
                        @if (!string.IsNullOrEmpty(listItem.Property))
                        {
                            <!-- 反射获取属性值,处理空值 -->
                            @GetPropertyValue(item, listItem.Property)
                        }
                        else if (listItem.ChildContent != null)
                        {
                            <!-- 渲染自定义内容,传递当前数据项作为上下文 -->
                            @listItem.ChildContent(item)
                        }
                    </span>
                }
            </li>
        }
    </ul>
</div>

@code {
    private List<ListItem<TItem>> _registeredItems = new();

    // 泛型参数支持任意数据类型
    [Parameter] public IEnumerable<TItem> Items { get; set; } = Enumerable.Empty<TItem>();
    [Parameter] public RenderFragment ChildContent { get; set; }

    // 供子组件注册的方法
    public void AddListItem(ListItem<TItem> listItem)
    {
        _registeredItems.Add(listItem);
        StateHasChanged();
    }

    // 反射获取属性值,封装成方法避免重复代码
    private object GetPropertyValue(TItem item, string propertyName)
    {
        if (item == null) return string.Empty;
        var propertyInfo = typeof(TItem).GetProperty(propertyName);
        return propertyInfo?.GetValue(item) ?? string.Empty;
    }
}

3. 组件使用示例

<OrderedList Items="pagedResult.Items">
    <ListItem Header="Name" Property="Name" />
    <ListItem Header="Actions">
        @(item => 
        {
            <button type="button" @onclick="() => HandleEdit(item)">
                Edit
            </button>
            <button type="button" @onclick="() => HandleDelete(item)" class="ml-2">
                Delete
            </button>
        })
    </ListItem>
</OrderedList>

@code {
    private void HandleEdit(OrganizationResponse organization)
    {
        // 编辑逻辑
    }

    private void HandleDelete(OrganizationResponse organization)
    {
        // 删除逻辑
    }
}

额外建议

  • 样式定制:给组件添加CSS类(如示例中的ordered-list-container、list-header等),方便自定义布局和样式
  • 性能优化:如果数据量较大,可缓存反射的PropertyInfo,避免每次循环都调用GetType().GetProperty()
  • 排序功能:基于Sortable参数,在表头点击时触发排序逻辑,修改Items的排序状态
  • 空状态处理:添加@if (!Items.Any())分支,展示空数据提示

内容的提问来源于stack exchange,提问作者user3903484

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.08 11:35:26