vue 3虚拟滚动需替换v-for为专用组件或手动三部分结构:占位容器撑高、偏移内容区定位、v-for渲染可视项;推荐用recyclescroller/virtuoso,传items与item-size/item-heights,v-slot解构item,容器设固定高度。

Vue 3 模板中接入虚拟滚动,核心是“替换 v-for,用专用组件或结构包裹数据”,不依赖响应式遍历全部项。关键不是写法多复杂,而是模板层要配合底层计算逻辑——比如撑高容器、定位可见项、动态插槽传值。
用现成组件快速接入(推荐新手)
最省事的方式是直接使用 RecycleScroller 或 Virtuoso 这类已适配 Vue 3 的组件:
- 安装后,在模板里直接替换原
v-for列表 - 必须传
:items(数组)、:item-size(固定高度时)或item-heights(动态高度时) - 用
v-slot="{ item }"解构传递单条数据,内部写渲染逻辑,和写普通v-for几乎一样 - 父容器需设明确高度(如
height: 500px),否则滚动区域无法识别
手写模板结构(适合定制或学习原理)
若不用第三方库,模板需手动构建三部分:占位容器、偏移内容区、可视项循环:
- 用一个
<div class="virtual-scroll-container"> 做滚动容器,绑定 <code>@scroll - 内部放一个
<div class="placeholder">,高度设为 <code>:style="{ height: totalHeight + 'px' }"(即items.length * itemHeight) - 再放一个
<div class="virtual-scroll-content">,用 <code>:style="{ transform: `translateY(${offsetY}px)` }"控制位置 - 里面用
v-for渲染visibleItems(计算属性,只含当前可视范围的数据) - 每个列表项外层加
ref,并在挂载后通过ResizeObserver监听真实高度变化 - 模板中不能写死
height,要用:style="{ height: getItemHeight(item.id) + 'px' }"动态绑定 - 占位容器的高度不再是简单乘法,而是读取缓存的累计高度数组最后一项
- 别在虚拟滚动容器内再套一层
v-for或v-if嵌套过深——这会破坏可见项计算边界 - 不要给列表项加
key以外的响应式属性(比如:class="row.status"),频繁触发重渲染 - 插槽内容尽量轻量,避免在
v-slot内调用复杂函数或访问深层嵌套响应式对象 - 禁用
transition-group或动画类——虚拟滚动靠的是瞬时位移,动画会干扰 offset 计算
动态高度模板的特殊处理
当每行高度不同时,模板本身不变,但需配合 JS 层做两件事:
避免常见模板错误
很多卡顿其实源于模板写法不当:











