passive:true可让浏览器立即执行滚动等默认行为,避免等待JS执行;必须设置的事件是touchstart、touchmove和scroll,因它们默认可取消且易阻塞滚动。

直接在 touchmove、touchstart 或 scroll 事件监听中启用 passive: true,就能让浏览器跳过等待 JavaScript 执行的环节,立刻响应滚动,默认行为(如页面滑动)和 JS 回调并行运行,从而消除卡顿。
哪些事件必须加 passive:true
移动端最常出问题的是以下三类事件,它们默认可取消(cancelable = true),浏览器会保守地阻塞滚动等待 JS 执行完毕:
- touchstart:哪怕只监听不处理,也会触发“等待判定”机制
- touchmove:高频触发,不设 passive 时极易造成滚动掉帧
- scroll:尤其在容器内滚动(如 overflow: auto 的 div)时,需显式声明
正确写法与常见错误
使用对象参数形式,明确传入 { passive: true }。注意:不能混用旧式布尔参数,也不能漏掉大括号。
- ✅ 正确:
el.addEventListener('touchmove', handler, { passive: true }); - ❌ 错误:
el.addEventListener('touchmove', handler, true);(这是 useCapture,不是 passive) - ❌ 错误:
el.addEventListener('touchmove', handler, { passive: true, capture: true });(capture 和 passive 可共存,但 capture=true 在 touchmove 中极少需要,易引发逻辑混乱)
如果业务确实要阻止默认行为怎么办
比如自定义下拉刷新或手势缩放,需要调用 e.preventDefault(),那就不能设 passive: true。此时应:
- 只在真正需要拦截的元素上绑定非 passive 监听器(例如仅在下拉区域监听 touchstart/touchmove)
- 用
event.cancelable动态判断是否允许阻止:if (e.cancelable) e.preventDefault(); - 避免全局监听
document上的 touchmove 并无条件 preventDefault,这会直接禁用整个页面滚动
兼容性与移除监听器的注意事项
Chrome 51+、Firefox 49+、Safari 15.4+、Edge 79+ 均支持 passive 选项。IE 完全不支持,若需兼容 IE,可用特性检测 + 回退方案:
- 检测方式:
let supportsPassive = false; try { const opts = Object.defineProperty({}, 'passive', { get() { supportsPassive = true; } }); window.addEventListener('test', null, opts); } catch (e) {} - 移除监听器时,无需重复传 passive:
removeEventListener('touchmove', handler)即可,浏览器自动匹配原注册配置










