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

点击导航首项跳转至第三项时第二项出现active类高亮闪烁如何解决

你遇到的闪烁本质是两个原因叠加:

  1. 现有滚动监听逻辑是只要scrollTop大于区块的offsetTop - 50就更新当前高亮,平滑滚动过程中必然会经过第二个区块的阈值,触发第二个按钮高亮,滚动到第三个区块后才切换,所以出现闪烁。
  2. scroll事件触发频率极高,没有做防抖处理,频繁更新DOM类名也会放大闪烁感知。

以下是两种可行解决方案:

方案1:用IntersectionObserver替换scroll事件监听(更推荐)

IntersectionObserver是浏览器原生提供的交叉观察者API,专门用来判断元素是否进入视口,可以精准控制触发高亮的条件,不会因为滚动路过就误触发,性能也更好。
修改后的JS代码:

const sectionOne = document.querySelectorAll('.observe');
const buttonList = document.querySelectorAll('button');
const box = document.querySelector('.box');
// 点击跳转时的锁,避免滚动过程中触发高亮
let isJumpIng = false;

// 初始化交叉观察者
const observer = new IntersectionObserver((entries) => {
  // 跳转过程中直接返回,不处理
  if(isJumpIng) return;
  entries.forEach(entry => {
    // 当区块进入视口超过50%时才高亮对应按钮
    if(entry.isIntersecting && entry.intersectionRatio >= 0.5) {
      const currentId = entry.target.id;
      buttonList.forEach(btn => {
        btn.classList.remove('bg-red-500');
        if(btn.classList.contains(currentId)) {
          btn.classList.add('bg-red-500');
        }
      })
    }
  })
}, {
  root: box,
  threshold: 0.5 // 可视比例达到50%触发,可根据需求调整
})

// 给所有区块注册观察
sectionOne.forEach(item => observer.observe(item));

// 跳转函数修改,加锁
function goTo(element) {
  isJumpIng = true;
  element.scrollIntoView({ behavior: "smooth" });
  // 等滚动结束后解锁,根据滚动动画时长调整时间,一般平滑滚动是300-800ms
  setTimeout(() => {
    isJumpIng = false;
    // 解锁后手动触发一次当前可视区域的高亮修正
    const current = [...sectionOne].find(item => {
      const rect = item.getBoundingClientRect();
      const boxRect = box.getBoundingClientRect();
      return rect.top >= boxRect.top && rect.top <= boxRect.top + 150;
    })
    if(current) {
      buttonList.forEach(btn => {
        btn.classList.remove('bg-red-500');
        if(btn.classList.contains(current.id)) {
          btn.classList.add('bg-red-500');
        }
      })
    }
  }, 600)
}

// 记得删掉HTML里box的onscroll绑定,以及原来的myScroll函数

方案2:给原有scroll逻辑加防抖+跳转锁(改动最小)

如果不想改原有逻辑,只要加防抖和跳转锁就能解决闪烁问题:

const sectionOne = document.querySelectorAll('.observe');
const buttonList = document.querySelectorAll('button')
const box = document.querySelector('.box');
let isJumpIng = false;
// 防抖函数,300ms内多次触发只执行最后一次,时长可根据需求调整
function debounce(fn, delay = 300) {
  let timer = null;
  return function(...args) {
    clearTimeout(timer);
    timer = setTimeout(() => fn.apply(this, args), delay)
  }
}

const myScroll = debounce(function(e) {
  if(isJumpIng) return;
  let current = ""
  sectionOne.forEach((item) => {
    if (box.scrollTop >= (item.offsetTop - 50)) {
      current = item.getAttribute("id")
    }
  })

  buttonList.forEach((button) => {
    button.classList.remove("bg-red-500")
    if (button.classList.contains(current)) {
      button.classList.add("bg-red-500")
    }
  })
})

// 跳转函数加锁
function goTo(element) {
  isJumpIng = true;
  element.scrollIntoView({ behavior: "smooth" });
  setTimeout(() => {
    isJumpIng = false;
    // 手动触发一次滚动事件修正高亮
    myScroll()
  }, 600)
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.30 13:54:03