虚拟滚动是解决大规模列表卡顿的核心方案,通过仅渲染可视区域及缓冲区节点、用占位容器撑起高度来避免无效DOM;配合shallowRef、精准更新和分层架构实现高性能。

大规模列表卡顿,不是 Vue 响应式系统扛不住,而是你让浏览器一次性处理了本不该出现的 DOM。核心解法就一条:别渲染看不见的项。
只渲染可视区域,虚拟滚动是刚需
万级数据下,用户屏幕一次最多看到 20–50 条,却硬要挂上几万个 DOM 节点——内存暴涨、重排重绘频繁、滚动掉帧。虚拟滚动通过“占位 + 动态替换”解决这个问题:用一个高占位容器撑起整个滚动高度,只在可视区及上下缓冲区里渲染真实节点。
- 优先选成熟库:vue-virtual-scroll-list(轻量清晰)或 vue-virtual-scroller(功能全,支持动态高度)
-
keeps(缓冲区数量)别拍脑袋:建议设为
Math.ceil(容器高度 / 单项高度) + 10;太小快滚会闪白,太大失去优化意义 - 固定高度比动态高度快得多;若必须变高,用
sizeKey或预估平均高度 + 异步修正,避免滚动时反复测算
状态不参与渲染,源头减负
状态管理本身不拖慢页面,但把每条数据都套上 reactive、再全量丢进 v-for,等于主动给 Vue 加压。
分析 Vue 3 Composition API 使用情况——审计响应式模式、可组合函数设计、ref 与 reactive 的选择、计算属性、watcher 使用及组件……
- 纯展示场景:用 shallowRef 包裹原始数组,跳过深层响应式代理,初始化更快、内存更省
- 局部交互(如单行编辑):不给每项加响应式,只用一个
editingId: ref(null)记录当前 ID,样式和逻辑按需计算 - 别把
isHovered、isSelected这类瞬时 UI 状态塞进全局 store,组件内ref或纯 CSS:hover更合适
更新要精准,避免连带重绘
搜索、筛选、实时追加这些操作,一动就全量刷新列表,虚拟滚动效果直接归零。
立即学习“前端免费学习笔记(深入)”;
- 筛选/搜索结果用 computed 缓存,返回新数组引用(配合
shallowRef),避免无意义响应式触发 - 日志流追加数据后,调用虚拟列表的
scrollTo(0)或forceUpdate(),而不是靠watch刷新整个列表 - 批量操作(如全选删除):先收集 ID,再一次性提交 mutation,杜绝逐项触发更新和视图重绘
结构分层,比选哪个 store 更重要
把数据拆清楚,比纠结用 Pinia 还是 Vuex 更关键。
-
源数据层:原始、不可变,来自 API 或本地缓存,用
shallowRef或只读对象封装 - 逻辑层:处理筛选、排序、分页等计算,输出当前需要的子集,状态尽量精简
- 渲染层:只接收当前可视片段 + 少量交互状态(如编辑 ID),不持有全量数据


















