scroll-view 必须设固定高度,iOS 才赋予原生滚动权限;pages.json 中需配置 disableScroll: true 避免手势冲突;禁用 @touchmove.prevent 以保系统滚动;列表项须优化图片、key、阴影及高度。

scroll-view 必须设固定高度,否则 iOS 直接放弃原生滚动资格
很多卡顿根本不是代码逻辑问题,而是 scroll-view 没拿到系统级滚动权限。iOS WebKit 只给「有明确尺寸+可滚动」的容器开硬件加速通道。如果 scroll-view 高度是 auto 或靠 flex 布局“撑出来”,WebKit 就判定它“不配滚动”,退化成 JS 模拟滚动——一卡就灵。
正确做法:
-
scroll-view的父容器必须带height: 100vh或具体像素值(如height: 600px) -
scroll-view自身用flex: 1或height: 100%,但前提是父级高度已锁定 - 绝对不要写
style="height: auto"或依赖内容撑高 - 在 nvue 页面中,改用
height: 600px这类硬编码更稳
pages.json 里 disableScroll: true 是前提,否则页面和 scroll-view 抢手势
小程序环境里,页面默认自带滚动能力。当用户手指划下去,系统先问“要不要走页面级滚动?”——如果没关掉,scroll-view 就得等第一次滑动触发回弹后才接手,造成“二次才动”现象。
必须在 pages.json 对应页面配置里加:
{ "path": "pages/list", "style": { "disableScroll": true } }
注意:disableScroll 是页面级开关,不是组件属性;漏配或配错路径,整个优化就失效。
@touchmove 里乱调 preventDefault() 等于亲手拆掉滚动引擎
常见错误:为了“阻止页面跳转”或“统一处理方向”,在 scroll-view 外层或 body 上绑 @touchmove.prevent。这在 iOS 上等于对系统说:“别滚了,我自己来”,结果 JS 根本算不过来,帧率暴跌。
只在真要接管滚动时才用 e.preventDefault():
- 拖拽排序、手势缩放等自定义交互场景
- 监听滑动方向?用
Math.abs(deltaY) > 5判断后,不调preventDefault(),让系统继续原生滚动 - 嵌套滚动(比如横向 swiper 里套纵向 scroll-view)?确保事件冒泡不被意外拦截
列表项里藏了三个隐形卡顿源:图片、key、阴影
滑动卡顿常不来自滚动本身,而来自每一帧都要重绘的节点。真机上尤其明显,模拟器几乎不卡。
必须检查:
-
<image>必须加lazy-load属性,且 src 指向压缩后的 WebP(iOS 14+ 原生支持) -
v-for的:key不能用:key="index",得是稳定唯一 ID(如:key="item.id") - 避免在列表项里用
box-shadow或border-radius > 2px;可用transform: translateZ(0)触发 GPU 加速 - 每项高度必须固定(如
height: 120px),否则虚拟滚动无法准确计算可视区域
最隐蔽的坑:swiper-item 里塞满 scroll-view,又没控制渲染数量——哪怕只显示 1 页,其余页的 v-if 没写对,DOM 节点照常创建,内存和渲染压力一点没少。


















