卡顿根源在于 reactive 对大数据列表深度代理导致频繁 proxy 拦截;应改用 shallowref 管理原始数据、computed 缓存过滤结果、虚拟滚动减少 dom 渲染量,并确保过滤逻辑纯函数化、避免响应式副作用。

大型列表过滤卡顿,核心不是“怎么写过滤逻辑”,而是“响应式系统在频繁读写时如何不拖垮渲染”。Vue 3 的 reactive 默认对每个列表项做深度代理,1000 条数据就创建 1000 个 Proxy,每次 filter 都触发大量 get 拦截和依赖收集——这才是卡顿的根源。
用 shallowRef + 手动触发更新,切断无意义响应链
如果过滤结果只在用户点击“搜索”或输入完成(防抖后)才需要刷新视图,就不该让整个原始列表保持深度响应式。
- 把原始大数据列表用
shallowRef包裹,它只对.value赋值响应,内部属性修改完全不触发更新 - 过滤逻辑放在计算属性或方法里,返回一个新数组(非响应式),再赋值给另一个
ref用于渲染 - 这样 filter 过程不触发任何依赖收集,CPU 时间全花在计算上,而不是 Proxy 拦截上
过滤结果用 computed 缓存,避免重复执行
用户连续输入时,若没做防抖,可能一秒内触发十几次 filter。直接在模板里写 v-for="item in list.filter(...)" 会导致每次 render 都重跑整个过滤函数。
递归分析 Vue 项目组件依赖,从入口文件生成组件层级图,支持 Vue 2/3,输出组件名、文件路径和属性。适用于分析组件结构、排查依赖或了解项目架构。
- 把过滤逻辑抽到
computed中,依赖搜索关键词和原始列表 - 只要关键词不变、原始列表没变,computed 就直接返回缓存结果,不重新执行 filter
- 配合
shallowRef原始数据,还能避免 computed 内部访问 item 属性时触发深层 track
可视区域按需响应:虚拟滚动 + 分片更新
即使过滤后只剩 500 条,一次性渲染仍可能卡顿。此时响应式本身不是瓶颈,DOM 渲染量才是。
- 用虚拟滚动组件(如
vue-virtual-scroll-list),只渲染当前可视的 20 条 - 把过滤后的列表传给虚拟滚动器,它内部用
key和index管理局部更新,不依赖每项的响应式 - 如需高亮匹配关键词,可把高亮逻辑移入 renderItem 函数,不走响应式路径
避免在过滤中修改响应式对象
常见错误:在 filter 回调里直接改 item.isMatch = true,尤其当 item 来自 reactive 数组时,每次赋值都触发 set 拦截+更新通知。
- 过滤应是纯函数:输入原始数据 + 条件 → 输出新数组,不产生副作用
- 如需标记状态(比如“已匹配”),用独立的
Map或Set存 ID,渲染时查表,绕过响应式代理 - 必要时用
markRaw标记不需要响应式的对象(如从接口直接拿到的列表项)
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!









