当其他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ć
相关产品推荐
相关产品推荐

