You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

求助:实现滚动到视图时触发圆形进度条动画

实现滚动触发的无限循环圆形进度条动画(基于jQuery Circle Progress)

嘿,我来帮你搞定这个圆形进度条的问题!你想要实现滚动到可见区域才触发动画+动画无限循环,之前用waypoints和AOS没效果,咱们一步步来解决它~

问题分析

你现在的代码一页面加载就会直接播放所有进度条的动画,既没有绑定滚动触发逻辑,也没有循环动画的处理。咱们需要解决两个核心需求:

  • 当进度条滚动到视口可见范围时,才启动动画
  • 动画完成后自动重复,实现无限循环

完整解决方案代码

首先确保你已经正确引入了jQuery和circleProgress插件(如果还没引入,要先加在<head>或者</body>结束前)。

1. HTML结构(保留你的原有结构,无需大改)

<div class="card">
  <div class="circle">
    <div class="bar"></div>
    <div class="box"><span></span></div>
  </div>
  <div class="text">HTML</div>
</div>
<div class="card css">
  <div class="circle">
    <div class="bar"></div>
    <div class="box"><span></span></div>
  </div>
  <div class="text">CSS</div>
</div>
<div class="card js">
  <div class="circle">
    <div class="bar"></div>
    <div class="box"><span></span></div>
  </div>
  <div class="text">Javascript</div>
</div>
<div class="card ps">
  <div class="circle">
    <div class="bar"></div>
    <div class="box"><span></span></div>
  </div>
  <div class="text">Photoshop</div>
</div>
<div class="card pp">
  <div class="circle">
    <div class="bar"></div>
    <div class="box"><span></span></div>
  </div>
  <div class="text">Premiere Pro</div>
</div>
<div class="card sql">
  <div class="circle">
    <div class="bar"></div>
    <div class="box"><span></span></div>
  </div>
  <div class="text">MySQL</div>
</div>

2. CSS样式(让进度条和文字正确显示)

.card {
  display: inline-block;
  margin: 20px;
  text-align: center;
}
.circle {
  position: relative;
  width: 150px;
  height: 150px;
}
.circle .bar {
  position: absolute;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
}
.circle .box {
  position: absolute;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
  font-size: 24px;
  font-weight: bold;
}

3. jQuery代码(实现滚动触发+无限循环)

// 统一管理每个技能的目标进度值
const skillValues = {
  default: 0.80,
  css: 0.80,
  js: 0.70,
  ps: 0.85,
  pp: 0.80,
  sql: 0.65
};

// circleProgress基础配置
const baseOptions = {
  startAngle: -1.55,
  size: 150,
  fill: { gradient: ['#a445b2', '#fa4299'] },
  animation: { duration: 2000 } // 动画时长,可根据需求调整
};

// 判断元素是否在视口可见范围内的工具函数
function isInViewport(element) {
  const rect = element.getBoundingClientRect();
  return (
    rect.top <= (window.innerHeight || document.documentElement.clientHeight) &&
    rect.bottom >= 0
  );
}

// 单个进度条的动画循环逻辑
function animateCircle($bar, targetValue) {
  // 从0开始初始化进度条
  $bar.circleProgress({
    ...baseOptions,
    value: 0
  }).on('circle-animation-progress', function(event, progress, stepValue) {
    // 更新进度百分比文字
    $(this).parent().find("span").text(String(stepValue.toFixed(2).substr(2)) + "%");
  }).on('circle-animation-end', function() {
    // 动画结束后延迟1秒重新启动循环(可调整延迟时间)
    setTimeout(() => {
      // 只有元素还在视口内才继续循环
      if (isInViewport($bar[0])) {
        animateCircle($bar, targetValue);
      }
    }, 1000);
  });

  // 启动动画到目标进度值
  $bar.circleProgress('value', targetValue);
}

// 滚动监听事件:检测元素是否进入视口,触发对应动画
$(window).on('scroll', function() {
  $('.card').each(function() {
    const $card = $(this);
    const $bar = $card.find('.bar');
    // 用data属性标记是否已启动动画,避免滚动时重复触发
    if (!$card.data('animated') && isInViewport($card[0])) {
      $card.data('animated', true);
      // 获取当前技能的目标进度值
      const skillClass = $card.attr('class').split(' ')[1];
      const targetValue = skillValues[skillClass] || skillValues.default;
      animateCircle($bar, targetValue);
    }
  });
});

// 页面加载时主动触发一次滚动检测,避免元素一开始就在视口内不启动动画
$(window).trigger('scroll');

关键逻辑解释

  1. 视口检测isInViewport函数用来判断元素是否进入了用户可见区域,确保只有滚动到进度条时才启动动画。
  2. 无限循环:在circle-animation-end事件中设置延迟,重新调用动画函数,同时会再次检查元素是否在视口内,避免元素滚出后仍继续动画。
  3. 防重复触发:用data('animated')给每个卡片标记是否已启动动画,防止滚动时多次触发同一动画。
  4. 统一配置:把所有技能的进度值放在skillValues对象里,方便后续修改和维护。

这样调整后,你就能实现滚动触发动画+无限循环的效果啦~如果需要调整动画速度或者循环间隔,修改animation.duration或者setTimeout的时间即可。

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

火山引擎 最新活动