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

纯Vanilla JS实现指定区块垂直平滑滚动吸附效果求助

垂直全屏滚动吸附问题修复

问题背景

需要实现垂直全屏滚动吸附效果:鼠标滚轮或键盘上下键触发时,平滑滚动到上/下一个带data-section属性的区块(仅前3个section应用该效果),剩余section保持正常滚动。现有代码无法实现预期的立即吸附滚动效果。

现有代码的核心问题

  • 未阻止原生滚动行为,导致自定义滚动与浏览器默认滚动冲突
  • 未处理键盘上下键触发逻辑
  • 依赖固定窗口高度计算偏移,未考虑元素实际位置,窗口尺寸变化后会失效
  • 无滚动锁机制,连续滚动会触发多次动画
  • 未判断滚动范围,进入非目标区块后仍会强制吸附

修正后的完整实现

1. 必要的CSS设置

确保带data-section的区块占满视口:

html, body {
  margin: 0;
  padding: 0;
  scroll-behavior: smooth; /* 基础平滑滚动 */
}
[data-section] {
  height: 100vh;
  margin: 0;
  display: flex;
  flex-direction: column;
  justify-content: center;
  align-items: center;
  /* 可选:添加背景区分区块 */
  background: #f5f5f5;
}
[data-section]:nth-child(2) {
  background: #e8e8e8;
}
[data-section]:nth-child(3) {
  background: #dcdcdc;
}

2. 修复后的JavaScript代码

const sections = document.querySelectorAll('[data-section]');
let currentIndex = 0;
let isScrolling = false;
const scrollLockTimeout = 800; // 滚动动画锁定时长,匹配平滑滚动时间

// 获取每个目标区块的顶部偏移量
function getSectionOffsets() {
  return Array.from(sections).map(section => section.offsetTop);
}

let sectionOffsets = getSectionOffsets();

// 窗口resize时更新偏移量
window.addEventListener('resize', () => {
  sectionOffsets = getSectionOffsets();
});

// 处理滚动逻辑
function handleScroll(direction) {
  if (isScrolling) return;
  isScrolling = true;

  // 计算目标索引
  const targetIndex = direction === 'down' ? currentIndex + 1 : currentIndex - 1;

  // 检查目标索引是否在有效范围内
  if (targetIndex >= 0 && targetIndex < sections.length) {
    window.scrollTo({
      top: sectionOffsets[targetIndex],
      behavior: 'smooth'
    });
    currentIndex = targetIndex;
  } else {
    // 超出目标区块范围,释放滚动锁,恢复正常滚动
    isScrolling = false;
    return;
  }

  // 滚动完成后解锁
  setTimeout(() => {
    isScrolling = false;
  }, scrollLockTimeout);
}

// 监听鼠标滚轮事件
window.addEventListener('wheel', (e) => {
  const currentScrollTop = window.pageYOffset;
  const lastSectionBottom = sectionOffsets[sections.length - 1] + sections[sections.length - 1].offsetHeight;

  // 如果不在目标区块范围内,不阻止默认行为
  if (currentScrollTop < sectionOffsets[0] || currentScrollTop >= lastSectionBottom) {
    return;
  }

  e.preventDefault();
  const direction = e.deltaY > 0 ? 'down' : 'up';
  handleScroll(direction);
}, { passive: false });

// 监听键盘上下键事件
window.addEventListener('keydown', (e) => {
  const currentScrollTop = window.pageYOffset;
  const lastSectionBottom = sectionOffsets[sections.length - 1] + sections[sections.length - 1].offsetHeight;

  if (currentScrollTop < sectionOffsets[0] || currentScrollTop >= lastSectionBottom) {
    return;
  }

  if (e.key === 'ArrowDown') {
    e.preventDefault();
    handleScroll('down');
  } else if (e.key === 'ArrowUp') {
    e.preventDefault();
    handleScroll('up');
  }
});

3. 关键改进点

  • 阻止默认滚动冲突:在目标区块范围内阻止原生滚轮事件,避免滚动混乱
  • 动态偏移计算:使用元素实际offsetTop计算滚动位置,适配窗口尺寸变化
  • 滚动锁机制:防止连续滚动触发多次动画,确保每次滚动完成后才响应下一次操作
  • 范围判断:当滚动到目标区块之外时,自动恢复正常滚动行为
  • 支持键盘控制:添加上下箭头键触发滚动的逻辑

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.06 22:35:51