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

如何将递归Location列表渲染为带rowspan的格式化HTML表格?

解决方案:递归树形Location渲染带rowspan的HTML表格

这个需求的核心是准确计算每个节点对应的叶子节点总数(用来设置rowspan),同时通过递归逻辑逐层渲染表格行,确保父节点的单元格能跨占所有子节点对应的行数。

1. 修正叶子节点计数的扩展方法

你原来的GetDepth方法逻辑有点绕,咱们换个更清晰的实现:如果当前节点是叶子节点(没有子节点),返回1;否则递归累加所有子节点的叶子节点数量,这个数值就是该节点需要的rowspan值。

public static class LocationExtensions
{
    // 计算当前节点下的叶子节点总数(即需要的rowspan值)
    public static int GetLeafNodeCount(this Location location)
    {
        // 叶子节点:没有子节点,返回1
        if (location.ChildLocations == null || !location.ChildLocations.Any())
        {
            return 1;
        }
        
        // 非叶子节点:累加所有子节点的叶子节点数
        int count = 0;
        foreach (var child in location.ChildLocations)
        {
            count += child.GetLeafNodeCount();
        }
        return count;
    }
}

2. 视图中的递归渲染逻辑

在CSHTML视图里,我们可以用@helper定义一个递归渲染的辅助方法,它会根据当前节点的层级,决定如何输出<td>和<tr>标签,同时正确应用rowspan属性。

完整的视图代码如下:

@using WebApplication1.Controllers;
@using YourNamespace.Extensions; // 替换成你的扩展方法所在命名空间
@model List<Location>

@{
    ViewBag.Title = "Home Page";
}

<table class="table table-border">
    @foreach (var rootLocation in Model)
    {
        // 渲染根节点的第一行
        RenderLocationRow(rootLocation, 1);
    }
</table>

@helper RenderLocationRow(Location location, int currentLevel)
{
    var isLeaf = location.ChildLocations == null || !location.ChildLocations.Any();
    var rowSpan = location.GetLeafNodeCount();

    // 第一行:输出当前层级的单元格,以及后续层级的第一个子节点单元格(如果有)
    <tr>
        @if (currentLevel == 1)
        {
            <td rowspan="@rowSpan">@location.Name</td>
        }
        else if (currentLevel == 2)
        {
            <td rowspan="@rowSpan">@location.Name</td>
        }
        else
        {
            <td>@location.Name</td>
        }

        // 如果不是叶子节点,渲染第一个子节点的后续内容
        if (!isLeaf)
        {
            var firstChild = location.ChildLocations.First();
            // 递归渲染第一个子节点,层级+1
            RenderRemainingCells(firstChild, currentLevel + 1);
        }
    </tr>

    // 如果不是叶子节点,渲染剩下的子节点
    if (!isLeaf && location.ChildLocations.Count > 1)
    {
        foreach (var child in location.ChildLocations.Skip(1))
        {
            // 递归渲染其他子节点,层级保持当前层级(因为要补全该行的单元格)
            RenderLocationRow(child, currentLevel);
        }
    }
}

@helper RenderRemainingCells(Location location, int currentLevel)
{
    var isLeaf = location.ChildLocations == null || !location.ChildLocations.Any();
    var rowSpan = location.GetLeafNodeCount();

    if (currentLevel == 2)
    {
        <td rowspan="@rowSpan">@location.Name</td>
    }
    else
    {
        <td>@location.Name</td>
    }

    // 如果不是叶子节点,继续递归渲染子节点
    if (!isLeaf)
    {
        var firstChild = location.ChildLocations.First();
        RenderRemainingCells(firstChild, currentLevel + 1);
    }
}

3. 关键逻辑说明

  • GetLeafNodeCount方法:确保每个节点的rowspan等于其下所有叶子节点的数量,这样父单元格能准确跨占所有子节点对应的行数。
  • RenderLocationRow:负责渲染每一行的起始单元格,以及处理多个同级子节点的换行逻辑。
  • RenderRemainingCells:负责在同一行内渲染后续层级的单元格,确保树形结构的层级对应表格列的位置。

这个方案支持任意多级深度的Location结构,完全适配你实际场景的需求。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.28 06:15:09