加 .passive 能显著改善移动端滚动卡顿,因其告知浏览器不调用 preventDefault(),跳过 JS 执行等待,实现即时滚动响应;移动端 touchmove/scroll 高频触发,若未设 passive,浏览器会逐次阻塞等待回调执行,导致明显延迟。

直接加 .passive 就能显著改善移动端滚动卡顿,核心是告诉浏览器“我不会调用 preventDefault()”,让它跳过等待 JS 执行的阻塞步骤,立刻响应滚动。
为什么移动端滚动特别需要 .passive
移动端 touchmove 和 scroll 事件每秒可触发上百次。浏览器默认认为你可能要阻止滚动(比如做下拉刷新或禁止滑动),所以每次都会等你的 JS 回调执行完再滚动——哪怕回调只是一行空语句,也会造成肉眼可见的延迟。
加上 .passive 后,浏览器不再查询、不等待、不阻塞,手指一动,页面即滚,帧率更稳。
怎么在 Vue 中正确使用 @scroll.passive
模板中直接写,无需额外配置:
-
基础写法:
<div @scroll.passive="onScroll">...</div> -
搭配防抖/节流更稳妥:即使用了
.passive,仍建议对onScroll做轻量节流(如 16ms 一次),避免高频触发逻辑影响主线程 -
别混用 .prevent 或 .stop:
.passive和.prevent冲突,因为后者本质就是调用preventDefault(),浏览器会报错并忽略passive: true
哪些场景必须加 .passive
以下情况不加就容易卡:
- 长列表页(商品瀑布流、信息流)的容器滚动监听
- 自定义下拉刷新区域(
@touchstart.passive+@touchmove.passive,但下拉触发时需临时切为非 passive) - 弹窗内可滚动内容(避免滚动穿透的同时保持内部滑动流畅)
- 任何绑了
@scroll或@touchmove却没调用preventDefault()的地方
补充:原生 JS 也要配 options
不用 Vue 时,记得显式传 { passive: true }:
el.addEventListener('scroll', handler, { passive: true });el.addEventListener('touchmove', handler, { passive: true });- 漏掉这个参数,Chrome 控制台会警告 "Unable to preventDefault inside passive event listener",且滚动依然滞后


















