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

Angular5动画进度条实现求助:滚动触发+0到目标值动画

解决Angular 5进度条滚动触发动画问题

Hey there! Since you're new to Angular 5 after using jQuery for a while, let's break this down step by step—no jQuery-style DOM hacking needed, we'll do this the Angular way.

第一步:实现进度条从0到指定值的动画

首先,我们先搞定进度条的动画逻辑。我们会用Angular的视图引用(@ViewChild)获取DOM元素,通过逐步递增数值的方式实现平滑动画,比直接修改样式更可控。

组件模板(HTML)

<!-- 进度条容器 -->
<div class="progress-container" #progressContainer>
  <div class="progress-bar" [style.width.%]="progressValue"></div>
</div>

组件样式(CSS)

.progress-container {
  width: 100%;
  height: 20px;
  background-color: #eee;
  border-radius: 10px;
  overflow: hidden;
}

.progress-bar {
  height: 100%;
  background-color: #4CAF50;
  transition: none; /* 用JS控制动画,关掉CSS过渡避免冲突 */
}

组件类(TypeScript)

先导入必要的Angular装饰器:

import { Component, ViewChild, ElementRef, OnInit } from '@angular/core';

然后编写核心逻辑:

@Component({
  selector: 'app-progress-bar',
  templateUrl: './progress-bar.component.html',
  styleUrls: ['./progress-bar.component.css']
})
export class ProgressBarComponent implements OnInit {
  progressValue = 0; // 当前进度值
  targetValue = 75; // 可替换为任意0-100的数值
  animationTriggered = false; // 标记动画是否已触发,避免重复执行

  @ViewChild('progressContainer') progressContainer!: ElementRef;

  ngOnInit() {
    // 监听window滚动事件
    window.addEventListener('scroll', this.checkViewport.bind(this));
  }

  // 检查元素是否进入视口
  checkViewport() {
    if (this.animationTriggered) return; // 已触发则直接返回

    const element = this.progressContainer.nativeElement;
    const rect = element.getBoundingClientRect();
    
    // 判断元素是否进入视口:顶部小于窗口高度,底部大于0
    const isInViewport = rect.top < window.innerHeight && rect.bottom > 0;
    
    if (isInViewport) {
      this.animateProgress();
      this.animationTriggered = true;
      // 动画触发后移除滚动监听,优化性能
      window.removeEventListener('scroll', this.checkViewport.bind(this));
    }
  }

  // 基础版进度条动画
  animateProgress() {
    const increment = 1; // 每次递增步长,越小动画越平滑
    const duration = 16; // 每步间隔时间(约60fps)

    const timer = setInterval(() => {
      if (this.progressValue >= this.targetValue) {
        clearInterval(timer);
        this.progressValue = this.targetValue; // 确保最终值准确
        return;
      }
      this.progressValue += increment;
    }, duration);
  }
}

进阶:更平滑的时间驱动动画

如果想要更均匀流畅的动画效果,可以把animateProgress替换为基于requestAnimationFrame的版本:

animateProgress() {
  const startTime = performance.now();
  const totalDuration = 1500; // 动画总时长(毫秒)

  const animateFrame = (currentTime: number) => {
    const elapsedTime = currentTime - startTime;
    const progressRatio = Math.min(elapsedTime / totalDuration, 1);
    this.progressValue = progressRatio * this.targetValue;

    if (progressRatio < 1) {
      requestAnimationFrame(animateFrame);
    } else {
      this.progressValue = this.targetValue;
    }
  };

  requestAnimationFrame(animateFrame);
}

关键知识点说明

  • @ViewChild:Angular中获取DOM元素的标准方式,替代jQuery的选择器,更符合组件化思想。
  • 视口检测:用getBoundingClientRect()获取元素位置,判断是否进入视口,避免了jQuery式的DOM操作逻辑。
  • 数据绑定:通过Angular的双向数据绑定自动更新DOM,比直接操作DOM更安全、更符合框架规范。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.25 04:25:02