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

原生JS开发滚动进度条时如何让循环内classList.add事件仅触发一次

问题根因

  1. 滚动事件触发频率极高,只要滚动位置落在对应区间内,每次滚动都会重复给.scroll-title绑定transitionend事件,同一个回调被绑定多次后,触发时就会执行多次。
  2. 同一标题区间内滚动时,会重复执行添加action类的逻辑,导致动画被反复触发。

解决代码

1. 新增全局变量

// 存储当前激活的标题索引,初始值为0对应默认的MENU
let activeIndex = 0;
// 提前检测好transition事件名,无需每次滚动重复计算
const transitionEnd = whichTransitionEvent();

2. 修改滚动事件逻辑

window.onscroll = function() {
  for (var i = 1; i < pageTitlesRif.length; i++) {
    if (window.pageYOffset > pageTitlesRif[i - 1] && window.pageYOffset < pageTitlesRif[i]) {
      // 只有切换到新标题区间时才执行动画逻辑
      if (i-1 !== activeIndex) {
        activeIndex = i-1;
        // 先移除可能残留的事件监听做兜底
        titleScroll.removeEventListener(transitionEnd, putClass, false);
        titleScroll.classList.add('action');
        // 绑定一次性事件监听,触发后自动解绑
        titleScroll.addEventListener(transitionEnd, putClass, {
          once: true,
          passive: true
        });
        titleScroll.innerText = pageTitlesText[activeIndex];
      }
      // 进度条更新逻辑保留,每次滚动更新更顺滑
      scroll.style.left = (pageTitlesRif[i-1] * tot / scrollHeight) + 'px';
      scroll.style.width = ((pageTitlesRif[i] - pageTitlesRif[i - 1])  * tot / scrollHeight) + 'px';
      // 匹配到区间后直接跳出循环,减少不必要的遍历
      break;
    }
  }
}

3. 回调函数增加兜底逻辑(兼容不支持once参数的老旧浏览器)

let putClass = function(){
  this.classList.remove('action');
  // 主动移除事件监听,避免重复触发
  this.removeEventListener(transitionEnd, putClass, false);
}

额外优化点

你原有代码中let totSide = bandSide.offsetHeight的bandSide变量未定义,没有用到的话可以直接删除该行,避免控制台报错。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.03 10:57:03