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

Angular12如何实现仅当元素进入视口时触发动画

Angular 12 滚动触发元素动画实现方案

以下是3种可落地的实现方案,优先推荐第一种,性能和复用性最优:

方案1:@angular/animations + Intersection Observer API(推荐)

无需额外引入第三方依赖,利用原生API实现高性能监听,不会造成滚动卡顿。

步骤1:导入动画模块

在app.module.ts中导入浏览器动画模块:

import { BrowserAnimationsModule } from '@angular/platform-browser/animations';

@NgModule({
  imports: [
    // 其他导入
    BrowserAnimationsModule
  ]
})
export class AppModule { }

步骤2:自定义滚动动画触发指令

封装通用指令复用逻辑,创建scroll-animation.directive.ts:

import { Directive, ElementRef, Input, OnInit } from '@angular/core';
import { AnimationBuilder, AnimationPlayer, style, animate } from '@angular/animations';

@Directive({
  selector: '[appScrollAnimation]'
})
export class ScrollAnimationDirective implements OnInit {
  // 可自定义传入动画配置
  @Input() animationConfig = [
    style({ opacity: 0, transform: 'translateY(30px)' }),
    animate('600ms ease-out', style({ opacity: 1, transform: 'translateY(0)' }))
  ];
  private observer: IntersectionObserver;
  private player: AnimationPlayer;

  constructor(private el: ElementRef, private animationBuilder: AnimationBuilder) { }

  ngOnInit(): void {
    // 初始化元素初始状态
    this.el.nativeElement.style.opacity = 0;
    // 初始化Intersection Observer
    this.observer = new IntersectionObserver((entries) => {
      entries.forEach(entry => {
        if (entry.isIntersecting) {
          // 元素进入视口时触发动画
          const factory = this.animationBuilder.build(this.animationConfig);
          this.player = factory.create(this.el.nativeElement);
          this.player.play();
          // 只触发一次就取消监听,需要重复触发可删除下一行
          this.observer.unobserve(this.el.nativeElement);
        }
      });
    }, { threshold: 0.1 }); // 元素10%进入视口就触发,可自行调整
    this.observer.observe(this.el.nativeElement);
  }

  ngOnDestroy(): void {
    this.observer?.disconnect();
    this.player?.destroy();
  }
}

步骤3:模板中使用

给需要触发动画的元素加上指令即可:

<!-- 默认淡入上移动画 -->
<div appScrollAnimation>
  滚动到我这里就会触发动画
</div>

<!-- 自定义动画效果 -->
<div [appScrollAnimation]="[
  style({ opacity: 0, transform: 'scale(0.8)' }),
  animate('400ms ease-out', style({ opacity: 1, transform: 'scale(1)' }))
]">
  自定义缩放淡入动画
</div>

方案2:第三方滚动动画库

如果不想自己封装逻辑,可以选择兼容Angular 12版本的开源滚动动画库,安装后按照文档给对应元素添加属性即可快速实现,支持的动画效果更丰富。

方案3:原生scroll事件监听(不推荐)

通过监听window的scroll事件,配合getBoundingClientRect()判断元素是否在视口内,需要额外加节流逻辑限制触发频率避免性能问题,仅适合非常简单的单页面场景。

注意事项

  • Intersection Observer API已经支持所有现代浏览器,如果需要兼容极低版本浏览器,可以引入对应的polyfill。
  • 动画触发阈值可以根据实际需求调整threshold参数,取值范围0-1,0代表元素刚进入视口就触发,1代表元素完全进入视口才触发。
  • 如果需要元素每次滚动进入视口都重复触发动画,删除指令中unobserve的逻辑即可。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.28 21:39:00