如何遍历嵌套对象内部列表并实现层级展开折叠展示
通用嵌套对象层级遍历与可折叠表格实现
核心思路
- 用递归遍历替代固定层级的
foreach,只要对象包含Items子列表属性,就自动向下遍历,适配任意嵌套深度 - 后端负责统一整理所有层级的对象数据,标记层级、是否含子节点;前端负责渲染表格并实现展开/折叠交互
后端递归遍历示例(C#)
先定义通用节点结构,用来传递给前端:
public class TreeNode { public string ObjectType { get; set; } // 类名,如"A""B" public string ObjectInfo { get; set; } // 对象展示信息,可自定义拼接属性 public int Level { get; set; } // 层级,用于前端缩进 public bool HasChildren { get; set; } // 是否存在子节点 public List<TreeNode> Children { get; set; } = new List<TreeNode>(); } // 核心递归遍历方法 public List<TreeNode> TraverseNestedObjects(object root, int level = 0) { var nodes = new List<TreeNode>(); // 生成当前节点信息 var currentNode = new TreeNode { ObjectType = root.GetType().Name, ObjectInfo = GetObjectDisplayText(root), Level = level, HasChildren = HasItemsProperty(root) }; nodes.Add(currentNode); // 递归遍历子节点(如果存在Items) if (currentNode.HasChildren) { var items = GetItemsValue(root); foreach (var item in items) { nodes.AddRange(TraverseNestedObjects(item, level + 1)); } } return nodes; } // 辅助方法:判断对象是否有Items属性 private bool HasItemsProperty(object obj) { return obj.GetType().GetProperty("Items") != null; } // 辅助方法:获取Items属性的值 private IEnumerable<object> GetItemsValue(object obj) { var prop = obj.GetType().GetProperty("Items"); return prop?.GetValue(obj) as IEnumerable<object> ?? Enumerable.Empty<object>(); } // 辅助方法:自定义对象展示文本(可按需修改) private string GetObjectDisplayText(object obj) { // 示例:拼接除Items外的所有公共属性 var props = obj.GetType().GetProperties() .Where(p => p.Name != "Items") .Select(p => $"{p.Name}: {p.GetValue(obj)}"); return string.Join(", ", props); }
前端可折叠表格实现(HTML+JS)
将后端返回的TreeNode列表渲染为可折叠表格:
<style> .indent { margin-left: 20px; } .collapse-btn { cursor: pointer; color: #0066cc; text-decoration: underline; } .child-row { display: none; } </style> <table border="1" cellpadding="8" width="100%"> <thead> <tr> <th>操作</th> <th>层级</th> <th>类类型</th> <th>对象详情</th> </tr> </thead> <tbody id="treeTable"> <!-- 后端渲染内容插入此处 --> </tbody> </table> <script> // 替换为后端返回的JSON节点数据 const treeNodes = /* 后端接口返回的TreeNode列表JSON */; // 渲染表格 function renderTreeTable() { const tbody = document.getElementById('treeTable'); tbody.innerHTML = ''; treeNodes.forEach(node => { const row = document.createElement('tr'); row.dataset.level = node.level; row.dataset.hasChildren = node.hasChildren; // 操作列:展开/折叠按钮 const actionTd = document.createElement('td'); if (node.hasChildren) { const btn = document.createElement('span'); btn.className = 'collapse-btn'; btn.textContent = '+'; btn.onclick = () => toggleChildRows(node.level); actionTd.appendChild(btn); } row.appendChild(actionTd); // 层级列 const levelTd = document.createElement('td'); levelTd.textContent = node.level; row.appendChild(levelTd); // 类类型列(带缩进) const typeTd = document.createElement('td'); typeTd.innerHTML = `<span class="indent" style="margin-left: ${node.level * 20}px">${node.objectType}</span>`; row.appendChild(typeTd); // 对象详情列 const infoTd = document.createElement('td'); infoTd.textContent = node.objectInfo; row.appendChild(infoTd); // 非根节点默认隐藏 if (node.level > 0) { row.classList.add('child-row'); } tbody.appendChild(row); }); } // 切换子节点显示/隐藏 function toggleChildRows(parentLevel) { const childRows = document.querySelectorAll(`tr[data-level="${parentLevel + 1}"]`); const parentBtn = document.querySelector(`tr[data-level="${parentLevel}"] .collapse-btn`); childRows.forEach(row => { row.style.display = row.style.display === 'none' ? '' : 'none'; // 递归切换更深层级(可选,按需开启) if (row.dataset.hasChildren === 'true') { const childBtn = row.querySelector('.collapse-btn'); childBtn.textContent = row.style.display === 'none' ? '+' : '-'; toggleChildRows(parseInt(row.dataset.level)); } }); // 更新父节点按钮符号 parentBtn.textContent = parentBtn.textContent === '+' ? '-' : '+'; } // 初始化渲染 renderTreeTable(); </script>
关键说明
- 递归通用性:无论嵌套层级是A→B→C→D还是更深,递归逻辑都会自动遍历所有节点,无需修改遍历代码
- 交互逻辑:通过节点
level属性区分层级,控制缩进范围;点击按钮时切换对应子层级的显示状态 - 扩展性:后端
GetObjectDisplayText可自定义对象展示内容,前端样式可按需调整缩进、按钮样式等
内容的提问来源于stack exchange,提问作者Dev
相关产品推荐
相关产品推荐

