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

当其他div可见时,如何彻底禁用目标div的非鼠标滚轮滚动(附Fiddle)

解决目标div在另一个div可见时的完整滚动禁用问题

这问题我之前也碰到过,咱们先搞清楚为啥现有代码不管用,再给你说不用透明覆盖层的解决办法:

为啥现有代码只能禁用鼠标滚轮?

你当前的代码只处理了wheel事件——也就是鼠标滚轮触发的滚动,但浏览器里能让div滚动的途径可不止这一种:

  • 拖拽滚动条是浏览器的原生行为,它直接修改元素的scrollTop/scrollLeft属性,根本不会触发wheel事件,所以你的拦截逻辑对它完全无效
  • 当div获得焦点后,按下箭头键、PageUp/PageDown这些按键时,浏览器会触发默认的滚动行为,这是通过keydown事件触发的,你的代码没处理这类事件,所以键盘滚动该咋滚还咋滚

不用透明覆盖层的完整解决方案

咱们得从拦截所有滚动触发事件和阻止原生滚动行为两个角度入手,分三步来:

1. 拦截所有能触发滚动的事件

给目标div绑定几个关键事件,在另一个div可见时阻止默认行为:

const targetDiv = document.getElementById('target');
const anotherDiv = document.getElementById('another');

// 通用的滚动拦截函数
function blockScroll(e) {
  // 只有当anotherDiv可见时才拦截
  if (anotherDiv.offsetParent !== null) {
    e.preventDefault();
    e.stopPropagation();
    return false;
  }
}

// 拦截鼠标滚轮
targetDiv.addEventListener('wheel', blockScroll, { passive: false });
// 兼容旧版浏览器的mousewheel事件
targetDiv.addEventListener('mousewheel', blockScroll, { passive: false });
// 拦截移动端触摸滑动
targetDiv.addEventListener('touchmove', blockScroll, { passive: false });

// 拦截键盘滚动按键
targetDiv.addEventListener('keydown', (e) => {
  // 列出所有能触发滚动的按键
  const scrollTriggerKeys = ['ArrowUp', 'ArrowDown', 'ArrowLeft', 'ArrowRight', 'PageUp', 'PageDown', 'Home', 'End'];
  if (scrollTriggerKeys.includes(e.key) && anotherDiv.offsetParent !== null) {
    e.preventDefault();
  }
});

注意:passive: false必须加上,否则有些浏览器会阻止你调用preventDefault()。

2. 处理拖拽滚动条的情况

上面的事件拦截管不了拖拽滚动条,因为这是浏览器直接修改滚动位置的原生行为。咱们可以监听scroll事件,在滚动发生时把div的位置强行重置回原来的状态:

// 保存初始滚动位置
let savedScrollTop = targetDiv.scrollTop;
let savedScrollLeft = targetDiv.scrollLeft;

targetDiv.addEventListener('scroll', () => {
  if (anotherDiv.offsetParent !== null) {
    // 强制滚回之前的位置
    targetDiv.scrollTop = savedScrollTop;
    targetDiv.scrollLeft = savedScrollLeft;
  } else {
    // 正常滚动时更新保存的位置
    savedScrollTop = targetDiv.scrollTop;
    savedScrollLeft = targetDiv.scrollLeft;
  }
});

这种方法会有一点点滚动抖动,但这是不用覆盖层的前提下最可行的方案。如果你能接受滚动条暂时隐藏,那更简单:直接动态修改overflow属性,禁用滚动时设为hidden,启用时恢复成auto或scroll,这样拖拽滚动条的问题直接就没了:

// 假设你有触发anotherDiv显示/隐藏的逻辑,在这个逻辑里同步切换滚动状态
function toggleScrollAccess() {
  targetDiv.style.overflow = anotherDiv.offsetParent !== null ? 'hidden' : 'auto';
}

3. 避免div意外获得焦点

如果目标div不需要响应键盘输入,给它加个tabindex="-1",这样它就不会通过Tab键获得焦点,从根源上避免键盘滚动的问题:

<div id="target" tabindex="-1">你的滚动内容</div>

总结一下

  • 问题根源:只拦截了鼠标滚轮的wheel事件,没处理键盘滚动和拖拽滚动条的原生行为
  • 解决思路:通过事件拦截+滚动位置重置(或动态修改overflow),实现无覆盖层的完整滚动禁用

内容的提问来源于stack exchange,提问作者Roberto Zvjerković

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.19 07:28:43