You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何结合虚拟滚动懒加载Angular独立组件?

Angular独立组件与CDK虚拟滚动懒加载实现示例

核心实现思路

结合CDK虚拟滚动的视口可见范围监听,动态导入独立组件(无需NgModule声明),通过ViewContainerRef在元素进入视口时创建组件实例,移出视口时销毁实例以节省资源。

完整代码示例

1. 定义独立SVG组件

所有懒加载组件需标记standalone: true,以圆形SVG组件为例:

// circle-svg.component.ts
import { Component, Input } from '@angular/core';

@Component({
  selector: 'app-circle-svg',
  standalone: true,
  template: `
    <svg width="50" height="50">
      <circle cx="25" cy="25" r="20" fill="{{ fillColor }}" />
    </svg>
  `,
})
export class CircleSvgComponent {
  @Input() fillColor = 'blue';
}

同理可创建square-svg.component.ts、triangle-svg.component.ts等其他SVG组件,结构与上述一致。

2. 主虚拟滚动组件

实现视口监听、动态加载/销毁组件逻辑:

// virtual-scroll-lazy.component.ts
import { Component, ViewChild, ViewChildren, ViewContainerRef, QueryList, OnInit, OnDestroy } from '@angular/core';
import { CdkVirtualScrollViewport, ScrollingModule } from '@angular/cdk/scrolling';
import { CommonModule } from '@angular/common';

@Component({
  selector: 'app-virtual-scroll-lazy',
  standalone: true,
  imports: [CommonModule, ScrollingModule],
  template: `
    <cdk-virtual-scroll-viewport itemSize="50" class="viewport">
      <div 
        *cdkVirtualFor="let compName of componentNames; trackBy: trackByIndex"
        class="item"
        #itemContainer
      ></div>
    </cdk-virtual-scroll-viewport>
  `,
  styles: [`
    .viewport {
      height: 400px;
      width: 200px;
      border: 1px solid #eee;
    }
    .item {
      height: 50px;
      display: flex;
      align-items: center;
      justify-content: center;
    }
  `]
})
export class VirtualScrollLazyComponent implements OnInit, OnDestroy {
  @ViewChild(CdkVirtualScrollViewport) viewport!: CdkVirtualScrollViewport;
  @ViewChildren('itemContainer', { read: ViewContainerRef }) itemContainers!: QueryList<ViewContainerRef>;
  
  // 存储组件实例引用,用于销毁
  private componentRefs = new Map<number, any>();
  // 组件名称列表(对应业务中的字符串列表)
  componentNames = ['circle-svg', 'square-svg', 'triangle-svg'];

  ngOnInit() {
    // 监听滚动事件,更新可见组件
    this.viewport.elementScrolled().subscribe(() => this.updateVisibleComponents());
    // 初始加载可见区域组件
    this.updateVisibleComponents();
  }

  ngOnDestroy() {
    // 销毁所有动态创建的组件,避免内存泄漏
    this.componentRefs.forEach(ref => ref.destroy());
    this.componentRefs.clear();
  }

  trackByIndex(index: number) {
    return index;
  }

  private async updateVisibleComponents() {
    const { start, end } = this.viewport.getRenderedRange();

    // 销毁超出视口范围的组件
    this.componentRefs.forEach((ref, index) => {
      if (index < start || index >= end) {
        ref.destroy();
        this.componentRefs.delete(index);
      }
    });

    // 加载当前视口内未初始化的组件
    for (let i = start; i < end; i++) {
      if (!this.componentRefs.has(i)) {
        const compName = this.componentNames[i % this.componentNames.length];
        // 动态导入独立组件
        const module = await import(`./${compName}.component`);
        // 转换组件名称为大驼峰格式(匹配导出类名)
        const compClassName = compName.split('-')
          .map(word => word.charAt(0).toUpperCase() + word.slice(1))
          .join('') + 'Component';
        const compClass = module[compClassName];

        const container = this.itemContainers.get(i);
        if (container) {
          // 创建组件实例
          const compRef = container.createComponent(compClass);
          // 传递输入属性(示例:随机颜色)
          compRef.instance.fillColor = this.getRandomColor();
          this.componentRefs.set(i, compRef);
        }
      }
    }
  }

  private getRandomColor() {
    const colors = ['red', 'green', 'blue', 'orange', 'purple'];
    return colors[Math.floor(Math.random() * colors.length)];
  }
}

关键注意事项

  • 独立组件配置:所有懒加载组件必须设置standalone: true,无需添加到任何NgModule的declarations数组。
  • 路径匹配:动态导入的路径需与组件文件实际位置一致,确保编译时能正确解析。
  • 内存管理:必须在组件销毁时清理所有动态创建的组件实例,避免内存泄漏。
  • 性能优化:使用trackBy函数减少虚拟滚动时的DOM重绘,提升滚动流畅度。
  • 输入输出处理:通过componentRef.instance可直接设置组件输入属性或监听输出事件,满足业务交互需求。

内容的提问来源于stack exchange,提问作者Benjamin McFerren

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.22 22:30:58