
本文介绍如何使用 Odometer.js 实现数字在鼠标悬停时重新触发滚动动画,通过重置初始值并调用 update() 方法,让每个统计数字可重复、独立地播放滚动效果。
本文介绍如何使用 odometer.js 实现数字在鼠标悬停时重新触发滚动动画,通过重置初始值并调用 `update()` 方法,让每个统计数字可重复、独立地播放滚动效果。
要让 Odometer 数字在每次悬停(hover)时都重新滚动,关键在于避免“只播放一次”的静态状态。Odometer 默认仅在 value 变化时触发动画,而初始化后若目标值已达成,再次调用 update(targetValue) 将无效果。因此,必须在每次悬停前“欺骗” odometer,使其认为当前值与目标值不同。
✅ 正确实现逻辑
- 移除冗余的 window.onload 嵌套:原代码中 $(document).ready() 内又注册 window.onload,但此时 load 事件早已触发,导致初始化失效;
- 封装可复用的滚动函数:将 odometer 初始化与双阶段更新(随机中间值 → 目标值)封装为 odo_roll();
- 利用随机中间值重置状态:先 update(rnd(10, 99)) 强制 odometer 切换到一个非目标值,再立即 update(targetValue) 触发真实滚动;
- 绑定 hover 事件(推荐使用 mouseenter):避免 hover() 的 mouseleave 误触发,确保仅在进入时启动动画。
? 完整可运行代码示例
<!-- 引入依赖(务必按顺序) -->
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/odometer.js/0.4.7/themes/odometer-theme-train-station.css"><script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.7.1/jquery.min.js"></script><script src="https://cdnjs.cloudflare.com/ajax/libs/odometer.js/0.4.7/odometer.min.js"></script><script>
function rnd(min, max) {
return Math.floor(Math.random() * (max - min + 1)) + min;
}
function odo_roll() {
document.querySelectorAll('.odometer').forEach(el => {
const target = parseInt(el.getAttribute('data-value'), 10);
// 创建新 odometer 实例(注意:每次 hover 都新建,确保状态干净)
const odometer = new Odometer({
el: el,
value: 0,
format: '(,ddd)',
duration: 1800,
theme: 'train-station'
});
odometer.render(); // 必须显式渲染,尤其在动态创建时
// 先跳转至随机中间值,再滚动到目标值
odometer.update(rnd(1, target > 10 ? target - 1 : 5));
setTimeout(() => odometer.update(target), 100);
});
}
// 页面加载完成即初始化一次(首次展示)
$(document).ready(function() {
setTimeout(odo_roll, 300); // 稍微延迟确保 DOM 渲染完成
// 每次鼠标移入 .odometer 元素时重新滚动
$('.odometer').on('mouseenter', odo_roll);
});
</script><!-- HTML 结构(保持不变) --><section class="company-statistics"><div class="container">
<div class="stats-wrapper">
<div class="stats-content row">
<div class="col-6 col-md-4 col-lg-4 stat-item">
<div class="odometer" data-value="13">0</div>
</div>
<div class="col-6 col-md-4 col-lg-4 stat-item">
<div class="odometer" data-value="10">0</div>
</div>
<div class="col-6 col-md-4 col-lg-4 stat-item">
<div class="odometer" data-value="75">0</div>
</div>
<div class="col-6 col-md-4 col-lg-4 stat-item">
<div class="odometer" data-value="18">0</div>
</div>
<div class="col-6 col-md-4 col-lg-4 stat-item">
<div class="odometer" data-value="22">0</div>
</div>
<div class="col-6 col-md-4 col-lg-4 d-xl-none stat-item">
<div class="odometer" data-value="45">0</div>
</div>
</div>
</div>
</div>
</section>
⚠️ 注意事项与优化建议
- 性能考量:频繁新建 Odometer 实例可能带来开销。如需更高性能,可提前实例化并缓存,通过 odometer.reset()(需自定义或 patch)或 odometer.update(0) + odometer.update(target) 组合复用;
- 防抖处理:若用户快速进出多个数字,可添加简单防抖(如 clearTimeout(hoverTimer)),避免动画堆积;
- 无障碍友好:悬停动画对键盘/屏幕阅读器用户不可见,建议辅以 focus 事件支持,提升可访问性;
- CSS 主题适配:确保引入的 Odometer CSS 主题与设计风格一致,可自定义 .odometer 字体、颜色、行高等。
通过以上方法,每个 .odometer 元素都能在悬停时独立、流畅、可重复地执行数字滚动动画,显著增强数据展示的交互感与视觉吸引力。










