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

如何在scroll-behavior: smooth场景下区分滚动来源并控制scroll事件

解决手动滚动触发scroll事件、锚点平滑滚动不触发的需求

需求场景:页面绑定了scroll事件,同时通过scroll-behavior: smooth实现锚点链接的平滑滚动,需要让scroll事件仅在用户手动滚动时执行,点击锚点触发的平滑滚动过程中不执行该事件。

解决方案思路

通过标记滚动来源的状态变量,结合scrollend事件监听滚动结束,来控制scroll事件的执行逻辑:

  1. 点击锚点链接时,标记当前是「程序触发的滚动」
  2. scroll事件触发时,先判断状态,若为程序滚动则跳过执行
  3. 监听scrollend事件,在平滑滚动结束后重置状态,恢复手动滚动的事件处理

修改后的完整代码

HTML

<!DOCTYPE html>
<html>
  <head>
    <title>Parcel Sandbox</title>
    <meta charset="UTF-8" />
    <link rel="stylesheet" href="./src/styles.css" />
  </head>

  <body>
    <nav>
      <ul>
        <li><a href="#section1">Section 1</a></li>
        <li><a href="#section2">Section 2</a></li>
        <li><a href="#section3">Section 3</a></li>
      </ul>
    </nav>

    <section id="section1">Section 1</section>
    <section id="section2">Section 2</section>
    <section id="section3">Section 3</section>
  </body>
</html>

CSS

html {
  scroll-behavior: smooth;
}

body {
  font-family: Arial;
}

section {
  display: flex;
  justify-content: center;
  align-items: center;
  height: 150vh;
  font-size: 40px;
  color: #fff;
}

section:nth-of-type(1) {
  background-color: black;
}

section:nth-of-type(2) {
  background-color: grey;
}

section:nth-of-type(3) {
  background-color: black;
}

JavaScript

let isProgrammaticScroll = false;

function scrollHandler() {
  // 如果是程序触发的滚动,直接返回不执行逻辑
  if (isProgrammaticScroll) return;
  console.log("scroll");
}

const throttledScrollHandler = throttle(scrollHandler, 200);

window.addEventListener("scroll", throttledScrollHandler);
window.addEventListener("click", (e) => {
  const anchor = e.target.closest("a");
  if (anchor && anchor.getAttribute('href').startsWith('#')) {
    isProgrammaticScroll = true;
    console.log("clicked");
  }
});

// 监听滚动结束事件,重置状态
window.addEventListener("scrollend", () => {
  isProgrammaticScroll = false;
});

function throttle(callback, delay) {
  let timer = null;

  return function throttledFunc(...args) {
    if (timer) {
      return;
    }

    timer = setTimeout(() => {
      callback(...args);
      clearTimeout(timer);
      timer = null;
    }, delay);
  };
}

关键说明

  • isProgrammaticScroll变量用来区分滚动是用户手动触发还是锚点平滑滚动触发
  • 点击锚点时设置状态为true,此时scroll事件触发会直接跳过执行
  • scrollend事件会在平滑滚动完全结束后触发,此时重置状态为false,确保后续手动滚动能正常触发scroll事件
  • 对锚点链接做了额外判断(href以#开头),避免误触普通链接的点击事件

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.26 13:20:04