Angular不使用mat-tree如何实现无限嵌套自定义树模型

实现无限层级嵌套树方案
不依赖mat-tree实现任意深度树渲染的核心方案是递归组件:树形结构的每个节点渲染逻辑完全一致,将单节点逻辑抽为独立组件后,组件可以在自身模板内调用自身,自动适配无限层级,不需要硬编码固定层数。
具体实现步骤
- 定义通用树节点数据结构
所有层级的节点统一使用相同结构,保证递归时数据格式一致:interface TreeNode { name: string; children?: TreeNode[]; // 可自行扩展id、联系人信息等业务字段 } - 编写可递归的单节点组件
以Angular为例,新建独立的树节点组件,接收单个节点数据作为输入,自身处理展开收起、hover交互,碰到有子节点的场景直接嵌套调用自身:
组件逻辑代码(tree-node.component.ts):
组件模板代码(import { Component, Input } from '@angular/core'; @Component({ selector: 'app-tree-node', templateUrl: './tree-node.component.html', styles: [` .tree-children { padding-left: 20px; /* 左缩进区分层级,可自行调整数值 */ } .expand-icon { display: inline-block; width: 16px; font-size: 12px; } `] }) export class TreeNodeComponent { @Input() node: TreeNode; isExpanded = false; showActionBtns = false; toggleExpand() { if (this.node.children?.length) { this.isExpanded = !this.isExpanded; } } handleMouseEnter() { this.showActionBtns = true; } handleMouseLeave() { this.showActionBtns = false; } }tree-node.component.html):<div class="tree-node"> <!-- 当前节点内容区,复用原有父节点的交互逻辑 --> <div class="tree-node-content" (mouseenter)="handleMouseEnter()" (mouseleave)="handleMouseLeave()" > <p class="phonebook-title" (click)="toggleExpand()"> <!-- 展开收起标识,可替换为自定义图标 --> <span class="expand-icon" *ngIf="node.children?.length"> {{ isExpanded ? '▼' : '▶' }} </span> {{ node.name }} <!-- 原有新增、编辑、删除等操作按钮放在此处,通过*ngIf="showActionBtns"控制显示 --> </p> </div> <!-- 子节点渲染区:展开且存在子节点时渲染 --> <div class="tree-children" *ngIf="isExpanded && node.children?.length"> <!-- 遍历子节点,递归调用当前组件,自动适配任意深度嵌套 --> <app-tree-node *ngFor="let child of node.children" [node]="child" ></app-tree-node> </div> </div> - 在业务页面使用树组件
原有页面不需要再写多层嵌套循环,直接遍历根节点数组传入递归组件即可:<div class="phonebook-tree"> <app-tree-node *ngFor="let rootNode of phonebookTreeModelArray" [node]="rootNode" ></app-tree-node> </div>
补充说明
- 递归渲染不会触发死循环,只要树形数据不存在循环引用(即某节点的children数组中包含自身或上层祖先节点)即可,常规业务接口返回的树形结构均满足该要求。
- 如果需要保留“同层级同时仅展开一个节点”的逻辑,只需要给递归组件加输出事件,节点触发展开时通知父级关闭同层级其他节点的展开状态即可。
- 若需要默认展开指定节点,可在节点数据中增加
defaultExpanded标识,在组件初始化时读取该标识给isExpanded赋初始值。
内容的提问来源于stack exchange,提问作者niki tmb
相关产品推荐
相关产品推荐

