ASP.NET MVC中递归渲染树形结构为导航菜单的实现方法
树形导航菜单递归实现方案
整体实现分为两个核心环节:先把数据库查出来的扁平层级数据转成嵌套树形结构,再通过视图递归渲染出目标菜单结构。
后端递归构造树形结构
首先定义菜单数据模型,新增子节点集合字段存储下级数据:
public class MenuNode { public int Id { get; set; } public string Name { get; set; } public int? ParentId { get; set; } public List<MenuNode> Children { get; set; } = new(); }
用递归方式组装树结构,逻辑是先找所有根节点(Parent为null的节点),再递归给每个节点挂载它的直接子节点:
/// <summary> /// 递归加载指定节点的所有子节点 /// </summary> private void AttachChildNodes(MenuNode parent, List<MenuNode> allFlatNodes) { // 找出当前节点的直接子级 var directChildren = allFlatNodes.Where(n => n.ParentId == parent.Id).ToList(); parent.Children = directChildren; // 递归给每个子节点挂载它自己的子级 foreach (var child in directChildren) { AttachChildNodes(child, allFlatNodes); } } /// <summary> /// 构造完整菜单树 /// </summary> public List<MenuNode> BuildMenuTree(List<MenuNode> flatDataFromDb) { // 先取出所有顶级根节点 var rootNodes = flatDataFromDb.Where(n => n.ParentId == null).ToList(); foreach (var root in rootNodes) { AttachChildNodes(root, flatDataFromDb); } return rootNodes; }
控制器中查询数据库的扁平数据,构造为树结构后传入视图:
public IActionResult NavMenu() { // 替换为你自己的数据库查询逻辑,取出所有菜单数据 var flatMenuData = _yourDbContext.MenuTable.ToList(); var menuTree = BuildMenuTree(flatMenuData); return View(menuTree); }
视图层递归渲染菜单
通过递归分部视图实现层级渲染,避免在主视图写嵌套循环逻辑。
- 新建递归分部视图
Views/Shared/_MenuNode.cshtml,强类型绑定为单个MenuNode:
@model MenuNode <td> <div class="menu-item">@Model.Name</div> @* 存在子节点时,新增一行递归渲染所有子节点 *@ @if (Model.Children.Any()) { <tr> @foreach (var child in Model.Children) { <partial name="_MenuNode" model="child" /> } </tr> } </td>
- 主页面视图(
NavMenu.cshtml)强类型绑定为List<MenuNode>,渲染根节点:
@model List<MenuNode> <table class="nav-table"> @foreach (var rootNode in Model) { <tr> <partial name="_MenuNode" model="rootNode" /> </tr> } </table>
- 加基础样式匹配需要的表格布局:
.nav-table { border-collapse: collapse; min-width: 300px; } .nav-table td { border: 1px solid #e5e7eb; padding: 10px 16px; vertical-align: top; min-width: 100px; } .menu-item { font-weight: 500; }
按照给出的测试数据,最终渲染的结构和期望的导航菜单完全一致:根节点name1在第一行,name2、name3在第二行,name4作为name2的子节点嵌套在name2单元格的下一行。
内容的提问来源于stack exchange,提问作者ELOL
相关产品推荐
相关产品推荐

