虚拟滚动必须用 scroll-view(小程序/跨端)或 list(nvue),固定行高、稳定 key、拆分 setdata,否则必然卡顿白屏。

直接用 v-for 渲染几百条数据,真机上卡顿、白屏、内存暴涨是必然结果——这不是代码写得不够“优雅”,而是平台层面对 DOM 节点数、响应式代理、setData 序列化这三道硬闸的物理限制。
scroll-view + offsetTop 是跨端唯一能跑通的虚拟滚动方案
uni-app 没有原生虚拟列表,vue-virtual-scroller 这类库依赖 document 和 CSS transform,在小程序和 App 端直接报 document is not defined 或样式错乱。所有“虚拟列表”组件(包括 uView、z-paging)底层都是基于 scroll-view 手动算索引实现的。
-
scroll-view必须设固定高度(如height: 600rpx),且scroll-y="true",否则@scroll不触发 - 禁用
enable-back-to-top:它会劫持滚动事件,导致@scroll回调失灵 - 行高必须固定(比如
80rpx),动态高度要用z-paging的cell-height-mode="dynamic",但性能下降明显 - 监听
@scroll,用Math.floor(event.detail.scrollTop / 80)得到可视起始索引,再取前后各 3–5 条作缓冲区(总渲染 ≤ 11 条) - 用
height: calc(80rpx * 总数)撑开滚动条,空<view></view>占位,避免 DOM 节点爆炸
key 必须是稳定唯一 ID,:key="index" 是状态错乱的根源
Vue diff 时复用组件实例,:key="index" 在增删、排序、过滤后必然导致 input 内容漂移、switch 状态错位、图片加载错图——这不是 bug,是 key 不稳定引发的必然行为。
- 正确写法:
:key="item.id"或:key="item.sn",后端接口必须返回带唯一标识的字段 - 如果后端没给
id,至少用:key="item.timestamp + '-' + item.content.slice(0,10)"做弱唯一拼接 - 严禁用
Array.indexOf()或Math.random()生成伪 key
nvue 下必须用 list 组件,scroll-view 在 App 真机上必然卡顿
App 端 nvue 中,scroll-view 仍是 WebView 封装,根本触不到原生复用机制:iOS 触发 WKWebView 强制重排,Android 常报 OutOfMemoryError 或白屏闪退——加 -webkit-overflow-scrolling: touch 完全无效,nvue 不走 Web 渲染路径。
-
list底层调用 iOSUITableView/ AndroidRecyclerView,天然支持懒加载、局部更新、内存回收 - 必须设固定行高(如
height="120"),否则渲染失败或空白 - 禁止嵌套
scroll-view、swiper,手势冲突会导致滑动失效 - 图片必须用
image标签(不是img),开启lazy-load和mode="aspectFill" - 下拉刷新需包裹
<refresh></refresh>,上拉加载监听@scrollbottom并加防抖:if (this.loading || this.noMore) return
setData 和响应式开销比 DOM 更容易被忽略
真机卡顿、模拟器不卡,大概率不是渲染问题,而是 setData 超限或 Vue 响应式追踪崩了。小程序单次 setData 上限通常 2MB,而 Vue 对每个 item 都要建立响应式代理——500 条含 10 个字段的对象,光代理开销就能拖垮内存。
- 别把整个列表塞进一个 data 字段(如
this.listData = allItems),改用this.visibleData = visibleItems+this.totalHeight = 80 * allItems.length拆开管理 - 滚动回调里别直接赋值
this.visibleData = ...,包一层this.$nextTick(() => { this.visibleData = ... })防setData冲突 - 列表项里避免
watch、深层computed、或嵌套 3 层以上的响应式对象 - 新增页数据用
this.list.push(res.data),不要this.list = this.list.concat(res.data)—— 后者会重建整个响应式数组
最常被跳过的其实是“行高必须固定”和“key 必须稳定”这两条——它们不炫技、不涉及新组件,但只要漏掉一个,虚拟滚动就退化成更糟的错乱滚动。











