关键在于条件化调用 preventDefault() 并合理配置 passive 选项:全局无条件阻止 touchmove 会禁用原生滚动;应绑定到具体容器、加判断逻辑,确保 CSS 具备可滚动基础(高度+overflow),iOS 需 -webkit-overflow-scrolling: touch,嵌套滚动需防冒泡干扰。

关键在于不盲目阻止默认行为,只在真正需要干预时才调用 preventDefault(),并确保事件监听器配置合理。
检查 touchmove 事件是否无条件阻止默认行为
很多滑动失效源于类似这样的代码:
错误写法:
document.addEventListener('touchmove', function(e) { e.preventDefault(); });
它会全局禁用所有原生滚动。正确做法是加判断条件,并优先使用 passive 选项:
- 给监听器加上
{ passive: false }仅当确实要接管滚动逻辑时才设为false - 绝大多数场景应设为
{ passive: true }(默认值),让浏览器自行处理滚动 - 若需条件拦截,例如只在某个区域拖拽时禁用滚动,必须明确判断触发元素和手势意图
确保滚动容器具备可滚动的 CSS 基础
即使 JS 没问题,样式缺失也会让页面“看起来滑不动”:
- 目标容器必须有明确高度(如
height: 300px或max-height: 80vh) - 设置
overflow-y: auto或scroll,且不能被父级的overflow: hidden覆盖 - iOS 设备务必添加
-webkit-overflow-scrolling: touch启用平滑滚动 - 避免
body或html上设置overflow: hidden
排查嵌套滚动与事件冒泡干扰
多个可滚动区域嵌套(如外层 ScrollView + 内层列表)容易因事件拦截错位导致整体失灵:
- 不要在 document 级别监听
touchmove并直接preventDefault - 把事件监听绑定到具体容器上,例如
listEl.addEventListener('touchmove', handler) - 在 handler 中通过
e.target判断是否属于本容器内容,再决定是否拦截 - 必要时用
e.stopPropagation()阻止事件冒泡,但慎用,避免影响外层滚动
用开发者工具快速验证是否 JS 干预过度
打开 Chrome 或 Safari 的开发者工具,在控制台运行:
console.log('Scroll height:', document.documentElement.scrollHeight, 'Client height:', document.documentElement.clientHeight);
如果 scrollHeight ≤ clientHeight,说明内容没撑开页面,不是 JS 拦截问题;否则再检查:
- 执行
getEventListeners(document)查看是否有全局touchmove监听器 - 搜索源码中
preventDefault出现位置,确认其包裹条件是否严谨 - 临时注释可疑监听器,刷新测试滑动是否恢复

















