1

我的父组件有一个非二叉树节点(树的根)作为子节点。每个节点可以有 0 个或多个节点类型的子节点,并且子节点可以折叠或展开。此外,在我的父组件中,有一个按钮可让您折叠树中所有节点的所有子节点或展开所有子节点。

我有一个枚举,它标记整个树是否折叠(通过按钮)、整个树是否展开(通过按钮),或者树状态是否是手动控制的(与此问题无关)。

枚举看起来像这样:

export enum TreeStatus{
  Collapsed,
  Expanded,
  Manual
}

父组件.ts:

export class ParentComponent implements OnInit {
  root: Node;
  public treeStatus= TreeStatus.Collapsed;   //in the beginning, every node in the tree has children collapsed
  public isAnyNodeChildrenCollapsed = true;  //checks if any node has children collapsed(mainly used for manual toggle)

  onExpandAll() {
    this.treeStatus= TreeStatus.Expanded;
    this.isAnyNodeChildrenCollapsed = false;
  }

  onCollapseAll(){
    this.treeStatus= TreeStatus.Collapsed;
    this.isAnyNodeChildrenCollapsed = true;
  }
  
  ...
}

父组件.html:

<div>
  <button *ngIf="!isAnyNodeChildrenCollapsed " (click)="onCollapseAll()">  //if all nodes have children expanded, we will see the button that allows us to collapse all
    Collapse All
  </button>
  <button *ngIf="isAnyNodeChildrenCollapsed " (click)="onExpandAll()">     //if at least one node has children collapsed, we will see the button that allows us to expand all
    Expand All
  </button>
</div>
<div>
  <tree-item [node]="root" [treeStatus]="treeStatus"></tree-item>            //the root of my tree
</div>

树-item.component.ts:

export class TreeItemComponent implements OnInit, OnChanges{
   @Input() node: Node;
   @Input() treeStatus: TreeStatus;
   public isChildrenCollapsed = true;  //initially, all nodes have children collapsed

   ngOnChanges(changes: SimpleChanges) {
    console.log(this.node.id + ": " + changes.treeStatus.previousValue + " => " + changes.TreeStatus.currentValue);   
    //this log above best displays the issue. When I click on Expand All, all nodes in my tree appear in the logs, but when I click Collapse All, even though this is the same callback method, only the root appears to detect the change.(even so, the toggle somehow happens regardless)

    if (changes.treeStatus && changes.treeStatus.currentValue!=NavigatorTreeStatus.Manual) {
      this.isChildrenCollapsed = !(changes.treeStatus.currentValue == NavigatorTreeStatus.Expanded);
      }
    }
  }

}

tree-item.component.html(基本 DFS 树解析):

<div>
//display node here
</div>
<div *ngIf="node.children.length > 0 && !isChildrenCollapsed">
  <tree-item *ngFor="let child of node.children"
             [node]="child" 
             [treeStatus]="treeStatus" 
  >
</div>

我根本无法理解为什么,当我点击Expand All,从而将 treeStatus 更改为 Expanded 时,ngOnChanged 正常工作并按预期传播到三个节点中的每个节点,但是当现在点击Collapse All时,这会触发相同的 ngOnChanges 回调方法,唯一检测到更改的节点似乎是根。

以下是日志的显示方式: 最初,当打开组件时,root id 的状态为 0(已折叠),而不是未定义:

2013777645:未定义 => 0

点击Expand All后,root Id 的值从 0(Collapsed) 更改为 1(Expanded),其余节点从 undefined 更改为 1(Expanded)

2013777645:0 => 1

2118369458:未定义 => 1

368241412:未定义 => 1

1860836078:未定义 => 1

1979885541:未定义 => 1

1316570423:未定义 => 1

360484732:未定义 => 1

506271756:未定义 => 1

现在,在点击Collapse All后,日志中只显示根,将值从 1(展开)更改为 0(折叠)。

2013777645:1 => 0

最后,如果我们现在再次点击Expand All ,则会出现与以前完全相同的日志,即使其他节点不应该具有未定义的 treeStatus 值,因为它之前已被分配了一个值。

2013777645:0 => 1

2118369458:未定义 => 1

368241412:未定义 => 1

1860836078:未定义 => 1

1979885541:未定义 => 1

1316570423:未定义 => 1

360484732:未定义 => 1

506271756:未定义 => 1

你能帮我理解我错过了什么吗?我真的希望你能从这个解释中理解这个问题。先感谢您!

4

1 回答 1

2

看起来你用 . 隐藏子节点ngIf。当ngIf为假时,您不仅是隐藏的组件(或模板),而且已被破坏。您可以在此处找到更多详细信息。

于 2021-02-23T17:40:24.627 回答