如何在ASP.NET Core中将自引用数据结构展示为Tree View?
解决方案:自引用Person类的树形视图实现
方法1:完善Tag Helper的递归渲染逻辑
你当前的Tag Helper已经处理了根节点,但缺少递归渲染子节点的核心逻辑。另外,不建议在Tag Helper中直接访问_context(违反MVC关注点分离原则),最好通过Tag Helper属性接收传递过来的Person列表,让控制器负责数据查询。
步骤1:重构Tag Helper,添加递归渲染方法
[HtmlTargetElement("people-tree")] public class PeopleTreeTagHelper : TagHelper { // 通过视图传递的Person列表 [HtmlAttributeName("people")] public List<Person> People { get; set; } public override void Process(TagHelperContext context, TagHelperOutput output) { output.TagName = "div"; var builder = new StringBuilder(); builder.Append("<ul class='treeview mb-1 pl-3 pb-2'>"); // 筛选并渲染所有根节点(Parent为null的节点) foreach (var rootPerson in People.Where(p => p.Parent == null)) { RenderPersonNode(builder, rootPerson); } builder.Append("</ul>"); output.Content.SetHtmlContent(builder.ToString()); } // 递归渲染单个Person节点及其子节点 private void RenderPersonNode(StringBuilder builder, Person person) { // 渲染当前节点的基础HTML builder.AppendFormat("<li><i class='fas fa-angle-right rotate' id='rotate-{0}'></i><span><i class='far fa-envelope-open ic-w mx-1'></i>{1}</span>", person.Id, person.Name); // 如果有子节点,递归渲染 if (person.Children != null && person.Children.Count > 0) { builder.Append("<ul class='treeview-child pl-3'>"); foreach (var child in person.Children) { RenderPersonNode(builder, child); // 递归调用,处理子节点 } builder.Append("</ul>"); } builder.Append("</li>"); } }
步骤2:在视图中使用Tag Helper
首先在_ViewImports.cshtml中注册你的Tag Helper(假设它在YourProject.TagHelpers命名空间下):
@addTagHelper *, YourProject
然后在HierarchicalDataStructure.cshtml视图中传递数据:
@model PersonListModel <people-tree people="@Model.People"></people-tree>
步骤3:保留原Controller Action(无需修改)
你的原Action已经正确获取了包含子节点的Person列表,直接复用即可:
public IActionResult HierarchicalDataStructure() { var people = new PersonListModel(_context) { People = _context.People.Include(i => i.Children).ToList() }; return View(people); }
方法2:使用前端组件渲染JSON数据
如果你已经能通过Action获取正确的树形JSON,可以写一个视图,用JavaScript递归渲染或者使用现成的树形组件(比如Bootstrap Treeview、jQuery Treeview等)。
步骤1:创建视图HierarchicalDataStructure.cshtml
@{ ViewData["Title"] = "People Hierarchy"; } <h1>Person Hierarchical Tree</h1> <div id="people-tree-container"></div> @section Scripts { <script> // 从后端获取树形JSON数据 fetch('@Url.Action("GetPeopleTreeJson")') .then(response => response.json()) .then(data => { renderTree(data.data, document.getElementById('people-tree-container')); addToggleEvents(); // 添加折叠/展开事件 }); // 递归渲染树形结构 function renderTree(nodes, container) { const ul = document.createElement('ul'); ul.className = 'treeview mb-1 pl-3 pb-2'; nodes.forEach(node => { const li = document.createElement('li'); li.innerHTML = ` <i class='fas fa-angle-right rotate'></i> <span><i class='far fa-envelope-open ic-w mx-1'></i>${node.Name}</span> `; if (node.Children && node.Children.length > 0) { const childUl = document.createElement('ul'); childUl.className = 'treeview-child pl-3'; renderTree(node.Children, childUl); li.appendChild(childUl); } ul.appendChild(li); }); container.appendChild(ul); } // 添加折叠/展开交互 function addToggleEvents() { document.querySelectorAll('.rotate').forEach(icon => { icon.addEventListener('click', function() { const parentLi = this.closest('li'); parentLi.classList.toggle('open'); }); }); } </script> }
步骤2:新增返回JSON的Controller Action
public IActionResult GetPeopleTreeJson() { var rootPeople = _context.People .Include(i => i.Children) .Where(x => x.Parent == null) .ToList(); return Json(new { data = rootPeople }); }
步骤3:添加基础样式(可选)
为了让树形结构更美观,添加以下CSS实现折叠/展开的视觉效果:
.treeview-child { display: none; /* 默认隐藏子节点 */ } .treeview li.open > .treeview-child { display: block; } .rotate { cursor: pointer; transition: transform 0.2s; } .treeview li.open > .rotate { transform: rotate(90deg); }
内容的提问来源于stack exchange,提问作者Burak
相关产品推荐
相关产品推荐

