【问题标题】:Angular material CDK tree component with virtual scroll带虚拟滚动的角度材质 CDK 树组件
【发布时间】:2019-03-07 11:20:14
【问题描述】:

Angular Material CDK 树组件文档说:

“扁平树通常更容易设置样式和检查。它们对滚动变化也更友好,例如无限或虚拟滚动

任何想法如何将虚拟滚动应用于 CDK 平面树?

我有一棵巨大的树要渲染,现在它太慢了,当我递归打开所有节点时它会崩溃

我尝试了 @angular/cdk-experimental 但没有弄清楚如何将它与树组件集成

【问题讨论】:

  • 我也对这个话题感兴趣。缺少相关文档...我很确定这对专家来说很简单

标签: angular angular6 angular-material2 angular-cdk


【解决方案1】:

我知道这是旧的,但我在试图找出相同的确切事物时遇到了这个线程,经过大量实验,我找到了一个需要 的虚拟滚动平面树的基本工作示例如果您已经有一个工作的 cdk-tree,则只需很少的修改

我的解决方案的关键是放弃 cdk-tree 指令并直接将我的 MatTreeFlatDataSource 和 FlatTreeControl 与 *cdkVirtualFor 一起使用。您可能已经将这些对象设置为作为输入传递到 cdk-tree。 cdk-tree 实际上只是对这两个负责所有繁重工作的对象进行了非常轻的包装。

这是一个堆栈闪电战,举个更具体的例子: 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>
  • 最后,我找到了解决方案。有用!现在是时候从普通的树中实现细节了,它有很多功能,所以可能会出现一些麻烦。
【解决方案2】:

虚拟视口的主要功能是跟踪滚动事件并通知您当前在屏幕上的元素。使用此信息,您可以将树的数据源修改为仅是屏幕上的节点。

问题在于,目前,视口实际上只适用于高度一致的项目。当您展开树的一个节点时,该节点的高度与其余关闭的节点不一致。为了解决这个问题,您可以在节点展开时将子节点添加到虚拟视口的数据源中。

现在,我将忽略扩展节点的问题。

要使用树获得基本的虚拟滚动,请将其添加到您的模板中:

<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 with result希望这足以让您入门!

【讨论】:

  • 这种方法的一个小问题:renderedRangeStream 在 Angular 区域之外运行,因此您可能在渲染树节点上的更改检测方面遇到问题。您可以通过注入 CdkVirtualForOf 作为 view-child 并订阅其 viewChange observable 来解决此问题。
  • 我看到这种方法的一个问题是 mat-tree 可以是递归的,而这种方法只会减少根元素的长度。如果第二层有很多项目,这种方法根本无助于滚动。
【解决方案3】:
  • npm install @angular/cdk@7.0.0ng add @angular/cdk@7.0.0
  • 将滚动模块导入您的应用程序app.module.ts
    • import { ScrollingModule } from '@angular/cdk/scrolling';
    • 在@ngmodule 中的导入中添加ScrollingModule
  • 在 HTML 文件中添加您的 cdk-virtual-scroll-viewport

<cdk-virtual-scroll-viewport  style="height: 250px" itemSize="50" >
//your code will be here
    
</cdk-virtual-scroll-viewport>

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-01-31
    • 1970-01-01
    • 1970-01-01
    • 2020-02-06
    相关资源
    最近更新 更多