Angular 7应用下Mat Tree嵌套节点的全路径定向展开实现方案
深层嵌套Mat Tree节点全路径展开实现方案
核心实现逻辑
针对Angular 7版本的Mat Tree(嵌套数据源模式),实现深层节点全路径展开只需要两个核心环节,完全适配大数量级下的性能要求,不需要递归遍历全量树数据:
- 依托数据里
csrSectionNum的点分路径编码特性,直接拆解生成目标节点的全路径分级标识列表 - 顺着路径从根节点开始逐级匹配对应节点,将所有路径节点通过TreeControl设置为展开状态
可以完全解决现有逻辑仅能展开一级节点的问题,比如目标为9.2.1.2时,会依次展开9、9.2、9.2.1、9.2.1.2全路径上的所有节点。
分步实现代码
1. 拆解生成目标节点的全路径标识列表
利用csrSectionNum的点分格式,不需要从根开始递归找父节点,直接按规则拼接生成每一级的节点标识:
/** * 根据目标csrSectionNum生成全路径的节点标识列表 * @param targetCsrNum 示例:传入'9.2.1.2' * @returns 逐级路径数组 ['9', '9.2', '9.2.1', '9.2.1.2'] */ private getFullPathCsrList(targetCsrNum: string): string[] { const segments = targetCsrNum.split('.'); const pathList: string[] = []; segments.reduce((prevPath, currentSeg, index) => { const currentLevelPath = index === 0 ? currentSeg : `${prevPath}.${currentSeg}`; pathList.push(currentLevelPath); return currentLevelPath; }, ''); return pathList; }
这一步的时间复杂度和树总数据量无关,只和节点的嵌套深度有关,哪怕几万条树数据也不会产生性能开销。
2. 逐级收集路径上的匹配节点
拿到全路径标识列表后,从根节点开始收缩搜索范围,不需要扫描全树的所有分支:
/** * 从嵌套树数据中按路径收集所有匹配的节点实例 * @param rootTreeData 你的原始嵌套节点数组 * @param fullPathList getFullPathCsrList返回的路径列表 */ private getPathMatchedNodes(rootTreeData: any[], fullPathList: string[]): any[] { const matchedNodes: any[] = []; // 初始搜索范围为所有根节点 let searchRange = rootTreeData; for (const csrNum of fullPathList) { // 在当前搜索范围内找匹配csrSectionNum的节点 const currentNode = searchRange.find(node => node.csrSectionNum === csrNum); if (!currentNode) break; // 路径断裂时直接终止搜索 matchedNodes.push(currentNode); // 下一轮搜索范围收缩为当前节点的子节点列表,不遍历其他同级分支 searchRange = currentNode.children || []; } return matchedNodes; }
这个遍历逻辑的扫描范围仅覆盖目标路径上的分支,不会触达无关的同级节点,大数据量下依然能保持快速响应。
3. 调用TreeControl设置节点展开
拿到路径上的所有节点实例后,直接调用Mat Tree内置的展开方法即可,不需要手动修改数据源的展开标记:
// 假设你已经按嵌套树的初始化方式配置了TreeControl: // treeControl = new NestedTreeControl<any>(node => node.children); /** * 修改操作完成后调用,自动展开到目标节点 * @param targetCsrNum 修改完成的目标分区编号 * @param latestTreeData 最新的树数据源(保存接口返回后的最新数据) */ autoExpandToTargetSection(targetCsrNum: string, latestTreeData: any[]) { // 生成全路径标识列表 const fullPath = this.getFullPathCsrList(targetCsrNum); // 收集路径上的所有匹配节点 const pathNodes = this.getPathMatchedNodes(latestTreeData, fullPath); // 逐个设置节点为展开状态 pathNodes.forEach(node => { this.treeControl.expand(node); }); }
常见适配注意点
- 当前使用的是嵌套结构的TreeControl,
expand()方法只要传入对应的节点引用就可以生效,不需要额外维护节点ID和实例的映射表 - 避免为了匹配节点写全树递归逻辑,这种方式在大数量级下会出现明显的卡顿,利用
csrSectionNum的路径特性可以把扫描范围降到最低 - 触发展开逻辑时一定要传入最新的树数据源,不要使用旧的缓存数据,否则会因为节点引用更新导致展开失效
- 之前的一级节点展开问题,本质是原逻辑只匹配了根节点层级的
csrSectionNum,没有顺着路径逐级匹配后续深层节点
内容的提问来源于stack exchange,提问作者Santhosh
相关产品推荐
相关产品推荐

