Angular Material CDK tree组件文档中提到:
"扁平树通常更容易进行样式和检查。 它们也更适合滚动变化,例如无限卷动或 虚拟卷动。"
有什么方法可以将虚拟滚动应用于CDK扁平树?
我有一个需要渲染的大型树,目前速度非常慢,当我递归地打开所有节点时,它会崩溃。
我尝试使用 < cdk-virtual-scroll-viewport > @angular/cdk-experimental,但没有想出如何将其与树组件集成。
Angular Material CDK tree组件文档中提到:
"扁平树通常更容易进行样式和检查。 它们也更适合滚动变化,例如无限卷动或 虚拟卷动。"
有什么方法可以将虚拟滚动应用于CDK扁平树?
我有一个需要渲染的大型树,目前速度非常慢,当我递归地打开所有节点时,它会崩溃。
我尝试使用 < cdk-virtual-scroll-viewport > @angular/cdk-experimental,但没有想出如何将其与树组件集成。
我知道这是过时的,但在尝试解决完全相同的问题时,我遇到了这个线程,并经过大量实验,我找到了一个基本工作示例,可以通过几乎滚动的平面树来实现 VERY LITTLE MODIFICATION(如果您已经有一个工作的 cdk-tree)。
我的解决方案的关键是放弃 cdk-tree 指令并直接使用我的 MatTreeFlatDataSource 和 FlatTreeControl 与 *cdkVirtualFor 直接使用。您可能已经设置好这些对象以将其作为输入传递给 cdk-tree。 cdk-tree 实际上只是围绕这两个对象的一个非常轻巧的包装器,这两个对象正在执行所有重活。
以下是 stackblitz,以获得更具体的示例: https://stackblitz.com/edit/angular-b5nkkd?file=src/app/app.component.html
它包含以下内容:
两个滚动平面树,从同一底层数据源绘制,并由相同的底层树控件控制(即,它们保存相同的数据,您对一个树所做的任何操作也将反映在另一个树中)
第一个树使用 cdk-tree 指令,但我无法弄清楚如何让其与 CDK 虚拟滚动一起工作,因此它会呈现所有节点
第二棵树没有使用cdk-tree,但我成功地只做了很少的更改就使虚拟滚动起作用。因此,您需要自己进行样式和一些基本逻辑的处理,但是如果您比较一下stackblitz中的模板代码差异,您会发现它并不那么糟糕。
我正在显示每个滚动容器呈现的节点数以证明虚拟滚动在其中一个上起作用而另一个上则没有。
<cdk-virtual-scroll-viewport> <my-node *cdkVirtualFor="let node of dataSource" [node]="node"><my-node> </cdk-virtual-scroll-viewport>
...会导致 cdk-virtual-scroll-content-wrapper
具有 flex-direction: row;
,从而在视口之外产生水平滚动。将 <my-node>
包装在 <div>
中可以解决这个问题:<cdk-virtual-scroll-viewport> <div *cdkVirtualFor="let node of dataSource"> <my-node [node]="node"><my-node> </div> </cdk-virtual-scroll-viewport>
- Jack<cdk-virtual-scroll-viewport itemSize="48" style="height: 200px;">
<ng-container *cdkVirtualFor="let item of fullDatasource"></ng-container>
<mat-tree [dataSource]="dataSource" [treeControl]="treeControl">...</mat-tree-node>
</mat-tree>
</cdk-virtual-scroll-viewport>
virtualForOf
,将 fullDatasource 传递给它,以便视口知道需要多高。这可能有点作弊,因为我认为 virtualForOf
的预期用途是模板包含要滚动的项目,但保持为空似乎也可以工作。 ngAfterViewInit() {
this.virtualScroll.renderedRangeStream.subscribe(range => {
console.log(range, 'range')
this.dataSource.data = this.fullDatasource.slice(range.start, range.end)
})
}
renderedRangeStream
,它在滚动更改时会发射一个范围。每当这种情况发生时,我们只需将数据源设置为适当的切片即可!请参考Stackblitz示例,希望能够帮助您入门!renderedRangeStream
在 Angular 区域之外运行,因此您可能会在渲染的树节点上遇到变更检测问题。您可以通过将 CdkVirtualForOf 注入为视图子组件,并订阅其 viewChange
可观察对象来解决此问题。 - Jon Rimmer