如何在视觉视口尺寸变化(触摸板pinch zoom)时禁用滚动?
禁用触摸板捏合缩放后的视觉视口滚动
你之前尝试的visualViewport的scroll事件调用preventDefault()无效,核心原因是该事件在滚动行为完成后才触发,此时浏览器的默认滚动操作已经执行,无法通过阻止事件来取消滚动。
以下是两种可行的解决方案:
方案一:重置视觉视口滚动位置(简单直接)
通过监听视觉视口的scroll和resize事件,强制将滚动位置重置为原点,从视觉上禁用滚动:
// 缩放完成后立即重置滚动位置 visualViewport.addEventListener('resize', () => { visualViewport.scrollTop = 0; visualViewport.scrollLeft = 0; }); // 一旦视觉视口发生滚动,立刻将位置重置为原点 visualViewport.addEventListener('scroll', () => { visualViewport.scrollTop = 0; visualViewport.scrollLeft = 0; });
注意:这种方法会有轻微的滚动抖动,但实现简单,无需区分输入事件类型。
方案二:拦截触发视觉视口滚动的输入事件(无抖动)
针对触摸板拖拽视觉视口的操作,通过底层输入事件拦截,同时保留页面内其他可滚动元素的功能:
document.addEventListener('touchmove', (e) => { // 判断当前目标元素是否为可滚动元素 const target = e.target; const isElementScrollable = (target.scrollHeight > target.clientHeight && getComputedStyle(target).overflowY !== 'hidden') || (target.scrollWidth > target.clientWidth && getComputedStyle(target).overflowX !== 'hidden'); // 仅当目标元素不可滚动时,阻止默认行为(避免视觉视口滚动) if (!isElementScrollable) { e.preventDefault(); } }, { passive: false }); // 补充拦截触摸板的指针操作 document.addEventListener('pointermove', (e) => { if (e.pointerType === 'touch') { const target = e.target; const isElementScrollable = (target.scrollHeight > target.clientHeight && getComputedStyle(target).overflowY !== 'hidden') || (target.scrollWidth > target.clientWidth && getComputedStyle(target).overflowX !== 'hidden'); if (!isElementScrollable) { e.preventDefault(); } } }, { passive: false });
该方案通过判断目标元素的滚动能力,只拦截针对视觉视口的拖拽操作,不会影响页面内其他可滚动元素的正常滚动。
补充说明:
overflow:hidden无效的原因是它控制的是元素的布局视口滚动,而视觉视口的滚动是浏览器级别的视口交互,不受元素CSS属性直接控制。
内容的提问来源于stack exchange,提问作者Hesam Soleymani
相关产品推荐
相关产品推荐

