Vue列表重复渲染致界面卡顿,寻求问题原因排查
从你提供的代码和现象来看,界面卡顿的核心原因是列表组件被不必要地重复渲染,且文本节点的渲染放大了性能开销,具体拆解如下:
1. Apollo查询触发多次数据更新,导致列表反复重渲染
你设置了fetchPolicy: 'no-cache',这意味着Apollo每次执行QUERY_MOST_FREQUENTLY_USED查询时,都会直接向服务器请求新数据,而非复用本地缓存。如果这个查询被多次触发(比如组件重新挂载、父组件状态变化、Apollo自动重取机制触发),result回调会多次执行,每次都会把新数组赋值给this.mostFrequentlyUsed。
Vue的响应式系统会监测到数组引用的变化,进而触发整个列表组件的重渲染——哪怕新数组和旧数组内容完全一致,只要引用不同,Vue就会判定数据已更新,重新渲染所有列表项。
2. 列表项的Key策略加剧了重渲染开销
你的v-list-tile用meal.hash作为key(这部分是合理的,因为hash具备唯一性),但v-divider用了index作为key。当数组被重新赋值时,即便每个meal的hash不变,Vue也会因为数组引用变化,销毁旧的列表项组件(包括内部的checkbox、text-field),再重新创建新的组件实例,而非复用已有组件。
这种“销毁-重建”的操作比单纯更新DOM昂贵得多,尤其是当列表项包含交互组件时,会带来明显的性能消耗。
3. 文本节点渲染的叠加开销
注释掉{{ meal.name }}后卡顿消失,是因为文本节点的渲染(结合Vuetify的v-list-tile-title样式计算、字体渲染)在多次重渲染的叠加下,成为了压垮性能的最后一根稻草。
当列表反复重渲染时,每个列表项的文本节点都需要重新计算布局、绘制到页面,这些操作的CPU开销比单纯的组件状态更新要高,所以去掉文本渲染后,卡顿现象明显缓解。
4. 响应式数据的重复监听开销
每次Apollo返回新的mostFrequentlyUsed数组时,Vue需要为数组中的每个对象重新添加响应式监听(因为每个对象都是新的引用)。这个过程平时不明显,但在多次重复触发的情况下,会累积额外的性能开销,进一步加剧卡顿。
内容的提问来源于stack exchange,提问作者ChromeKK

