如何实现滚动到对应区块时触发进度条动画显示的功能
滚动触发视口动画解决方案
你的原有代码会在页面加载完成后立即执行所有进度条的动画,只需修改JS逻辑,通过元素可视区域检测实现滚动触发即可,原有HTML、CSS代码无需调整。
优先方案:IntersectionObserver 实现(性能最优)
该API是浏览器原生提供的元素交叉检测接口,无需频繁计算滚动偏移,性能远好于传统scroll监听方案:
$(function() { const animatedClass = 'skill_animated'; // 初始化交叉观察器 const observer = new IntersectionObserver((entries) => { entries.forEach(item => { // 元素进入视口且未执行过动画时触发 if (item.isIntersecting && !$(item.target).hasClass(animatedClass)) { const $perBar = $(item.target); const targetWidth = $perBar.attr('per'); $perBar.addClass(animatedClass) .css('width', targetWidth + '%'); $perBar.find('.value').text(targetWidth + '%').css('opacity', '1'); } }) }, { threshold: 0.15 // 可自定义触发阈值:0-1之间,代表元素露出视口的比例 }) // 给所有进度条绑定观察 $(".skill_per").each(function() { observer.observe(this); }) });
兼容方案:scroll监听实现(兼容旧浏览器)
如果需要适配不支持IntersectionObserver的旧浏览器,可使用scroll事件+节流实现,注意添加节流逻辑避免性能损耗:
$(function() { const animatedClass = 'skill_animated'; const $perBars = $(".skill_per"); // 节流函数:控制滚动事件触发频率 function throttle(fn, delay) { let timer = null; return function() { if (timer) return; timer = setTimeout(() => { fn.apply(this, arguments); timer = null; }, delay) } } // 检测元素是否进入视口 function isInViewport(el) { const rect = el.getBoundingClientRect(); return ( rect.top >= 0 && rect.left >= 0 && rect.bottom <= (window.innerHeight || document.documentElement.clientHeight) && rect.right <= (window.innerWidth || document.documentElement.clientWidth) ) } // 检查所有未触发动画的进度条 function checkAnimate() { $perBars.not(`.${animatedClass}`).each(function() { if (isInViewport(this)) { const $perBar = $(this); const targetWidth = $perBar.attr('per'); $perBar.addClass(animatedClass) .css('width', targetWidth + '%'); $perBar.find('.value').text(targetWidth + '%').css('opacity', '1'); } }) } // 页面加载先执行一次,避免元素初始就在视口时不触发动画 checkAnimate(); // 滚动时绑定节流后的检测逻辑,100ms检测一次可自行调整 $(window).on('scroll', throttle(checkAnimate, 100)); });
两种方案都添加了动画已执行的标记类,避免元素反复进出视口时重复触发动画,不需要重复触发的话无需修改,需要重复触发移除
addClass相关逻辑即可。
内容的提问来源于stack exchange,提问作者nikitasalnikov
相关产品推荐
相关产品推荐

