passive: true通过告知浏览器“绝不调用preventdefault()”,解除对touchstart、touchmove、scroll等可取消事件的执行等待,使默认滚动行为与js回调并行运行,从而消除卡顿、提升帧率。

passive: true 是怎么让滚动变快的
浏览器在处理 touchmove、wheel、scroll 这类事件时,必须等 JavaScript 回调执行完,才能决定是否执行默认滚动行为——哪怕回调里只有一行空语句。这个“等待判定”过程会阻塞主线程,尤其在低端设备上,直接导致掉帧、延迟超 100ms。
passive: true 的作用就是提前告诉浏览器:“我绝不会调用 e.preventDefault()”,于是浏览器可以跳过等待,立刻触发滚动,同时在后台线程并行执行你的 JS 回调。这不是“加速 JS”,而是“解除阻塞”。实测在中低端安卓机上,touchmove 帧率能从 30fps 提升到 55fps 左右。
哪些事件加了 passive 才真正有效
只有那些默认可取消(cancelable === true)且常被用于滚动控制的事件,加 passive: true 才有实际意义。关键三类:
-
touchstart和touchmove:移动端最常见卡顿源,即使空监听器也会触发等待机制 -
wheel:鼠标滚轮事件,Chrome 控制台警告[Violation] Added non-passive event listener to a scroll-blocking 'wheel' event就是它 -
scroll:特别是监听容器内滚动(如overflow: auto的div),不设passive: true容易因频繁触发而卡顿
注意:click、input 等事件本身不阻塞滚动,加 passive 没效果,还可能误导后续维护者。
为什么写了 passive: true 却报 “Unable to preventDefault inside passive event listener”
这是最典型的误用信号:你在设置了 { passive: true } 的监听器里,仍然写了 e.preventDefault()。
此时浏览器会直接忽略该调用,并在控制台抛出警告。这不是兼容性问题,而是强制约束——passive: true 意味着你已承诺“不阻止默认行为”。如果你确实需要拦截(比如下拉刷新),必须:
- 只在必要元素上绑定非 passive 监听器(例如仅对下拉区域的
div绑定touchmove,而非整个document) - 改用
passive: false,并确保目标浏览器支持(iOS Safari 12.2+ 起才允许显式设false) - 用
e.cancelable动态判断:只有当e.cancelable === true时才调用e.preventDefault()
removeEventListener 时要不要传 passive
不需要。移除监听器时,removeEventListener 只认函数引用和事件类型,完全忽略 passive 配置项。
也就是说,下面这两行是等价的:
el.addEventListener('touchmove', handler, { passive: true });
el.removeEventListener('touchmove', handler);
但要注意:如果你用的是匿名函数,就根本没法 remove;如果用了 once: true,也无需手动 remove——它执行完自动注销。真正容易被忽略的是:全局监听 document 上的 touchmove 并无条件 preventDefault(),这会直接禁用整页滚动,且无法通过 passive 规避。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











