前端进阶之旅前端进阶之旅
  • 基础篇HTML/CSS/JS 打底
  • 进阶篇原理与工程化
  • 高频篇面试最常问的那批
  • 精选篇按模块收敛的总结
  • 手写篇常考代码手写实现
  • 面经篇真实面试问题复盘
  • AI 篇NEWAI 时代的前端考点
  • 历年面经NEW按年份追踪真实考点
  • 每日一题每天一道,攒手感
  • 专项自测100 题快速查漏
  • 小程序题库小程序专项刷题
  • 算法题库NEW在线编码即时判题
  • 知识卡片NEW碎片时间过考点
  • 面试题大全常见问题解析
  • AI 答疑NEW随时提问,即时解析
  • AI 模拟面试NEW模拟真实面试 + 报告
  • AI 定制路线NEW按你的简历现排
  • AI 知识地图NEW串起全站知识点
  • 原理篇React / Vue 源码拆解
  • HTTP从报文一路讲到 HTTPS
  • 浏览器渲染、事件循环、进程
  • 计算机基础Linux、网络、操作系统
  • 设计模式23 种模式怎么用
  • Node学习指南从环境搭建到服务端
  • NPM工作流script、依赖与发布
  • Docker容器化部署上手
  • Canvas图形与动画实战
  • 前端系统进阶学习大型项目工程化
  • 前端综合文章长期沉淀的实践文
  • 思维导图知识点全景图
  • 学习路线按图索骥不跑偏
  • AI 热点NEWAI 每日动态
  • 公众号动态公众号历史文章
  • 博客动态站长的技术博客
  • 开发者导航常用工具与文档站
  • 基础篇HTML/CSS/JS 打底
  • 进阶篇原理与工程化
  • 高频篇面试最常问的那批
  • 精选篇按模块收敛的总结
  • 手写篇常考代码手写实现
  • 面经篇真实面试问题复盘
  • AI 篇NEWAI 时代的前端考点
  • 历年面经NEW按年份追踪真实考点
  • 每日一题每天一道,攒手感
  • 专项自测100 题快速查漏
  • 小程序题库小程序专项刷题
  • 算法题库NEW在线编码即时判题
  • 知识卡片NEW碎片时间过考点
  • 面试题大全常见问题解析
  • AI 答疑NEW随时提问,即时解析
  • AI 模拟面试NEW模拟真实面试 + 报告
  • AI 定制路线NEW按你的简历现排
  • AI 知识地图NEW串起全站知识点
  • 原理篇React / Vue 源码拆解
  • HTTP从报文一路讲到 HTTPS
  • 浏览器渲染、事件循环、进程
  • 计算机基础Linux、网络、操作系统
  • 设计模式23 种模式怎么用
  • Node学习指南从环境搭建到服务端
  • NPM工作流script、依赖与发布
  • Docker容器化部署上手
  • Canvas图形与动画实战
  • 前端系统进阶学习大型项目工程化
  • 前端综合文章长期沉淀的实践文
  • 思维导图知识点全景图
  • 学习路线按图索骥不跑偏
  • AI 热点NEWAI 每日动态
  • 公众号动态公众号历史文章
  • 博客动态站长的技术博客
  • 开发者导航常用工具与文档站
首页程序员面试题库wheel 事件 preventDefault 自定义滚动
浏览浏览器事件系统

如何用 preventDefault 阻止滚轮事件引发的页面滚动,但保留自定义滚轮行为?需要注意什么?

在监听 wheel 事件的回调中调用 event.preventDefault() 可阻止页面滚动,但前提是该监听器未以 passive: true 注册,且需要自行实现滚动逻辑,否则会破坏滚动链。

前端进阶之旅 · 一题精讲更新于 2026.09.05
浏览器#事件系统#动画
先看核心答案
理解线索

wheel 事件的可取消与自定义滚动

  1. passive 选项为 true 时 preventDefault 无效
  2. 滚动链cancelable 事件阻止默认行为
  3. 自定义滚动必须手动更新滚动位置

只有 cancelable 为 true 的事件才可能被 preventDefault,且需在浏览器默认滚动前同步调用。

核心回答

先记住这个答案

要阻止滚轮触发页面滚动,应使用 addEventListener('wheel', handler, { passive: false }),并在 handler 内调用 preventDefault()。之后浏览器不再执行默认滚动,但必须自行处理滚动动画,例如更新 scrollTop 或使用变换实现自定义滚动。同时注意 wheel 事件可取消,但某些浏览器在连续滚动序列的后几个事件可能不可取消,且 passive: true 会使 preventDefault() 失效并产生警告。

  • 设置 passive: false 才能取消 wheel 事件
  • 阻止默认滚动后需自行实现滚动动画
  • 连续滚动序列中部分事件可能不可取消

wheel 事件与默认滚动的关系

wheel 事件在用户滚动鼠标滚轮或触摸板时触发,它是一个可取消事件(cancelable 属性通常为 true)。浏览器在派发该事件后,会检查事件是否被 preventDefault() 取消,若未取消则执行默认的滚动或缩放行为。因此,在监听器内调用 preventDefault() 是阻止页面滚动的标准方式。

但关键在于 addEventListener 的 passive 选项。当 passive 为 true 时,表示监听器不会调用 preventDefault(),从而让浏览器无需等待 JS 执行即可立即滚动,以提高性能。若此时强行调用 preventDefault(),不仅无效,还会在控制台产生警告。要禁止默认滚动,必须显式设置 { passive: false }。

自定义横屏滚动容器

场景:一个横向滚动的照片画廊,设计为使用鼠标滚轮垂直滚动来驱动水平移动,同时阻止页面原本的垂直滚动。输入:用户滚动滚轮,产生 wheel 事件,deltaY 为正表示向下。约束:页面主体不能因滚轮而上下移动,但容器需要根据 deltaY 增加或减少 scrollLeft。

处理:在容器上添加 addEventListener('wheel', handler, { passive: false }),handler 内调用 preventDefault(),然后更新 container.scrollLeft += deltaY。结果页面不再滚动,画廊水平滑动。需要自行处理惯性效果吗?不,默认无惯性,可附加动画。此方式避免了 scroll 事件的异步性,让位移与滚轮同步。

易失效条件与负滚动链

第一个风险是 passive 默认为 true 的情况并非所有浏览器都强制,Chrome 对 wheel 事件默认已为 true,touchstart/touchmove 也已默认 true。若通过网络库或框架绑定事件,可能默认设置了 passive,导致 preventDefault 静默失败。可用 addEventListener 显式传 { passive: false }。

第二个风险是“负滚动链”:当容器内部已到达滚动边界,滚轮继续滚动,事件默认会传播到父级进行“链式滚动”。若子容器调用了 preventDefault,则父级也不会滚动,但若子容器没有处理边界条件(如 scrollLeft 为 0 或最大),再阻止默认也会阻断页面整体滚动。因此要检查 scrollable 状态,在到达边界时释放事件,允许后续默认行为。但释放意味着需移除 preventDefault,可动态判断。代价是逻辑复杂化,需监听 wheel 并判断定位。

回答前,多想一步

容易答错的地方

以为只要调用 preventDefault 即可生效
若不将 listener 设为 passive: false,尤其在某些开发库或已设置 passive 的场景,preventDefault 调用被忽略,页面仍滚动。必须检查 addEventListener 的 options 对象。依据规范,passive 监听器中 preventDefault 不产生效果。
忽略滚动链,在子元素无边界时也禁止滚动
若子容器内内容不足或已到边界,仍调用 preventDefault 会阻止父容器滚动,导致页面整体卡死。正确做法是判断滚动位置是否还有空间,若无则不再 preventDefault,让滚轮默认行为继续。
试着用自己的话回答

面试官还会怎么问?

在 React 中如何绑定 wheel 事件并取消默认滚动?

React 的合成事件对 wheel 默认 passive 为 false,但需在监听函数中调用 event.preventDefault()。若在根元素使用文档级别,建议直接在原生节点上 addEventListener 并传 { passive: false },避免依赖合成事件。注意 React 17 后绑定到 root 容器,事件代理可能影响。

wheel 事件与 touchpad 的 inertia 效果如何处理?

preventDefault 会停止所有默认滚动,包括触摸板的惯性滚动。若需保留惯性,需自行计算速度并模拟,例如基于 deltaY 累积加速度进行动画。无法直接控制浏览器自身的惯性,只能实现类似的物理模拟。

如何判断当前 wheel 事件是否可能导致页面滚动(即是否存在滚动链)?

可检查 event.cancelable,但更可靠是判断当前元素及祖先是否有可滚动方向。需要检测 scrollHeight 与 clientHeight 差异,以及定位。但无标准同步方法,通常需要自行计算滚动边界。

从一道题,走向一组知识

把知识连起来

事件系统

什么时候你会主动在捕获阶段注册事件监听器而不是默认的冒泡阶段?

同属「事件系统」专题,接着看 事件捕获阶段 监听器使用场景 在具体场景中的处理方式。

事件系统

事件委托如何解决动态添加元素的监听问题?请给出一个具体实现思路。

同属「事件系统」专题,接着看 事件委托 动态添加元素 实现 在具体场景中的处理方式。

参考资料

  • Element: wheel event

示例用于理解所注明的运行环境与边界;延伸学习可结合原文中的更多案例。

本题目录
  1. 先记住这个答案
  2. wheel 事件与默认滚动的关系
  3. 自定义横屏滚动容器
  4. 易失效条件与负滚动链
  5. 容易答错的地方
  6. 面试官还会怎么问
  7. 把知识连起来
读懂,再试着讲出来

先看核心答案,再读代码。最后展开追问,检查自己有没有遗漏边界。

试着回答追问
浏览全部面试题理解原理,也关注真实的使用场景。回到顶部 ↑