如何实现页面滚动至环形进度条时触发动画效果
解决方案:滚动到组件位置再触发环形进度条动画
我来帮你搞定这个问题!你的核心需求是让环形进度条的动画只在用户滚动到该组件位置时才触发,而不是页面加载时直接跑完。下面是具体的实现方案:
核心思路
我们需要通过监听页面滚动事件,判断进度条组件是否进入了用户的视口范围,只有当组件可见时,才初始化并启动circleProgress动画。同时要给已执行过动画的元素做标记,避免重复触发。
修改后的完整代码
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script> <style> #skill-body{ padding: 10px; min-height: 80vh; color: #F0505C; background: #191315; } .skill-wrapper{ max-width: 1100px; flex-wrap: wrap; align-items: center; justify-content: space-between; margin: auto; display: flex; } .skill-wrapper .card{ width: calc(100% / 2); height: 300px; display: flex; align-items: center; justify-content: space-evenly; flex-direction: column; margin: auto; } .skill-wrapper .card .circle{ position: relative; height: 150px; width: 150px; border-radius: 50%; } .skill-wrapper .card .circle .box{ height: 100%; width: 100%; transform: translate(-50%, -50%) scale(0.9); border-radius: 50%; } .skill-wrapper .card .circle:hover .box{ transform: translate(-50%, -50%) scale(1.19) } .skill-wrapper .card .circle .box, .skill-wrapper .card .circle .box span{ position: absolute; top: 50%; left: 50%; transition: all 0.1s; } .skill-wrapper .card .circle .box span{ font-size: 30px; transform: translate(-50%, -50%); } .skill-wrapper .card .text{ font-size: 20px; } </style> <div class="sec" id="skill-body"> <div class="skill-wrapper"> <div class="card"> <div class="circle"> <div class="bar" data-thickness="8" data-value="0.78"></div> <div class="box"><span>0%</span></div> </div> <div class="text">Illustrator</div> </div> <div class="card ps"> <div class="circle"> <div class="bar" data-thickness="8" data-value="0.76"></div> <div class="box"><span>0%</span></div> </div> <div class="text">Photoshop</div> </div> </div> <script> // 工具函数:判断元素是否在视口内 function isElementInViewport(el) { var rect = el.getBoundingClientRect(); return ( rect.top <= (window.innerHeight || document.documentElement.clientHeight) && rect.bottom >= 0 ); } // 初始化单个环形进度条的动画 function initCircleProgress($bar) { if ($bar.data('animated')) return; // 避免重复执行动画 var value = parseFloat($bar.data('value')); var thickness = parseInt($bar.data('thickness')); $bar.circleProgress({ startAngle: -1.55, size: 150, value: value, fill: {color: "#F0515C"}, thickness: thickness }).on('circle-animation-progress', function(event, progress, stepValue){ $(this).parent().find("span").text(String(stepValue.toFixed(2).substr(2)) + "%") }); $bar.data('animated', true); // 标记该进度条已执行动画 } // 检查所有未执行动画的进度条,视口内的就启动动画 function checkCircles() { $('.circle .bar:not([data-animated="true"])').each(function() { if (isElementInViewport(this)) { initCircleProgress($(this)); } }); } // 页面加载完成后先检查一次(避免组件一开始就在视口内) $(document).ready(function() { checkCircles(); // 监听滚动事件,每次滚动都检测未执行的进度条 $(window).scroll(function() { checkCircles(); }); }); </script> </div>
关键修改点说明
- 数据属性统一配置:把进度条的
value和thickness放到元素的data-*属性里(比如data-value="0.78"),这样可以用统一的逻辑初始化所有进度条,不用单独写每个的配置。 - 视口检测工具函数:
isElementInViewport用来判断元素是否进入了用户可见的视口范围,这是触发动画的核心条件。 - 动画初始化封装:
initCircleProgress负责单个进度条的动画启动,并且用data-animated标记已执行,防止用户滚动来回时重复触发动画。 - 滚动监听与初始检查:页面加载后先执行一次检查(避免组件一开始就在视口内的情况),然后监听滚动事件,每次滚动都检测未执行的进度条,符合条件就启动动画。
这样修改后,只有当用户滚动到#skill-body组件的位置,环形进度条进入视口时,动画才会开始播放,完美解决你之前的问题!
内容的提问来源于stack exchange,提问作者Mun
相关产品推荐
相关产品推荐

