如何让jQuery数字计数脚本仅在元素进入视口时执行?
解决数字滚动组件仅在进入视口时启动的问题
我完全懂你的烦恼——页面一加载数字就滚完了,用户滚动到组件位置时根本看不到动画效果!下面给你两种实用方案,都能让计数动画只在组件进入用户视口时才触发,还能保证只执行一次,不会重复滚动。
方案一:使用Intersection Observer API(推荐,性能更优)
这是现代浏览器原生支持的API,能高效监听元素是否进入视口,不用频繁监听scroll事件,性能友好很多。
修改JavaScript代码
把原有的启动计数的代码替换成以下逻辑(原有的countTo插件代码保留不变):
jQuery(function ($) { // 自定义数字格式化逻辑(和原代码一致) $('.count-number').data('countToOptions', { formatter: function (value, options) { return value.toFixed(options.decimals).replace(/\B(?=(?:\d{3})+(?!\d))/g, ','); } }); // 计数函数(和原代码一致) function count(options) { var $this = $(this); options = $.extend({}, options || {}, $this.data('countToOptions') || {}); $this.countTo(options); } // 创建视口观察实例 const observer = new IntersectionObserver((entries) => { entries.forEach(entry => { // 元素进入视口,且未执行过计数时触发 if (entry.isIntersecting && !entry.target.classList.contains('count-started')) { $(entry.target).addClass('count-started').each(count); // 执行后停止监听该元素,节省资源 observer.unobserve(entry.target); } }); }, { threshold: 0.1 // 元素10%进入视口时触发,可按需调整 }); // 给所有计数元素添加监听 $('.timer').each(function() { observer.observe(this); }); });
关键说明
threshold: 0.1:表示元素有10%的部分进入视口就启动动画,你可以改成0(刚碰到视口就触发)或1(完全进入视口才触发)。count-started类:用来标记元素已经执行过计数,避免滚动时重复触发动画。
方案二:使用scroll事件监听(兼容旧浏览器)
如果需要兼容不支持Intersection Observer的旧浏览器,可以用这种方法:
步骤1:添加视口检测工具函数
在你的jQuery代码开头先加一个判断元素是否在视口的函数:
$.fn.isInViewport = function() { var elementTop = $(this).offset().top; var elementBottom = elementTop + $(this).outerHeight(); var viewportTop = $(window).scrollTop(); var viewportBottom = viewportTop + $(window).height(); // 判断元素是否至少有一部分在视口中 return elementBottom > viewportTop && elementTop < viewportBottom; };
步骤2:修改启动计数逻辑
把原有的启动代码替换成以下内容:
jQuery(function ($) { // 自定义数字格式化逻辑(和原代码一致) $('.count-number').data('countToOptions', { formatter: function (value, options) { return value.toFixed(options.decimals).replace(/\B(?=(?:\d{3})+(?!\d))/g, ','); } }); // 计数函数(和原代码一致) function count(options) { var $this = $(this); options = $.extend({}, options || {}, $this.data('countToOptions') || {}); $this.countTo(options); } // 监听滚动和页面加载事件 $(window).on('scroll load', function() { $('.timer:not(.count-started)').each(function() { if ($(this).isInViewport()) { $(this).addClass('count-started').each(count); } }); }); // 页面加载时先检查一次,避免元素一开始就在视口中 $(window).trigger('scroll'); });
关键说明
- 同时监听
scroll和load事件,确保页面加载时如果元素已经在视口中也能触发动画。 - 同样用
count-started类防止重复触发,避免滚动时动画反复执行。 - 这种方法会频繁触发scroll事件,性能略逊于方案一,优先推荐用方案一。
测试小提示
- 测试时可以把浏览器窗口调小,让组件一开始不在视口中,滚动到组件位置看动画是否正常触发。
- 如果动画没触发,可以调整视口检测的阈值(方案一的
threshold,方案二的判断条件)。
内容的提问来源于stack exchange,提问作者xXnikosXx
相关产品推荐
相关产品推荐

