You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在指定counter-value div进入视口时触发计数器且仅执行一次

解决方案:仅当计数器元素进入视口时执行一次动画

要实现这个需求,最佳方案是使用浏览器原生的Intersection Observer API——它专门用于监听元素是否进入视口,性能远优于传统的scroll事件监听,还能轻松确保代码只执行一次。

下面是修改后的完整代码:

// 封装原来的计数器逻辑为独立函数
function initCounters() {
  try {
    const counter = document.querySelectorAll(".counter-value");
    const speed = 2500; // 数值越小,动画越慢

    counter.forEach((counter_value) => {
      const updateCount = () => {
        const target = +counter_value.getAttribute("data-target");
        const count = +counter_value.innerText;

        // 计算增量,确保至少为1避免无限循环
        let inc = target / speed;
        if (inc < 1) {
          inc = 1;
        }

        // 更新计数直到达到目标值
        if (count < target) {
          counter_value.innerText = (count + inc).toFixed(0);
          setTimeout(updateCount, 1);
        } else {
          counter_value.innerText = target;
        }
      };

      updateCount();
    });
  } catch (err) {
    console.error("计数器初始化失败:", err); // 可选:添加错误日志便于调试
  }
}

// 创建Intersection Observer实例,监听元素进入视口
let countersInitialized = false; // 标记是否已经执行过计数器逻辑
const observer = new IntersectionObserver((entries) => {
  // 检查是否有任意一个计数器元素进入视口,且尚未初始化
  if (!countersInitialized && entries.some(entry => entry.isIntersecting)) {
    initCounters();
    countersInitialized = true; // 标记为已执行,避免重复触发
    observer.disconnect(); // 断开观察,释放资源
  }
}, {
  threshold: 0.1 // 当元素有10%进入视口时触发,可根据需求调整
});

// 开始观察所有计数器元素
document.querySelectorAll(".counter-value").forEach(el => {
  observer.observe(el);
});

// 额外处理:如果页面加载时元素已经在视口内,立即执行
if (!countersInitialized) {
  const isAnyCounterInViewport = Array.from(document.querySelectorAll(".counter-value")).some(el => {
    const rect = el.getBoundingClientRect();
    return rect.top < window.innerHeight && rect.bottom > 0;
  });
  if (isAnyCounterInViewport) {
    initCounters();
    countersInitialized = true;
    observer.disconnect();
  }
}

代码说明:

  • 封装逻辑:把原来的计数器动画代码放到initCounters()函数里,便于复用和控制执行时机
  • Intersection Observer:监听所有.counter-value元素,当其中任意一个进入视口(达到设置的阈值)时,执行计数器逻辑
  • 防止重复执行:用countersInitialized标志位确保代码只运行一次,执行后立即断开观察释放浏览器资源
  • 边界处理:额外检查页面加载时元素是否已经在视口内,避免错过触发时机
  • 错误优化:在catch块中添加了错误日志,便于调试(可选,你可以根据需要移除)

为什么不用scroll事件?

传统的scroll事件会在用户滚动时频繁触发,需要手动节流,性能较差;而Intersection Observer是浏览器原生优化的API,只会在元素进入/离开视口时触发,性能更优,代码也更简洁。

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.04 16:25:17