列表上拉刷新卡顿的根源是模板中链式调用触发全量响应式重收集和重复计算。应将过滤逻辑移至 computed 或方法中,精简依赖,优先服务端过滤,必要时节流或冻结数据。

为什么列表上拉刷新时过滤器会卡顿
不是过滤逻辑本身慢,而是每次刷新都触发全量响应式依赖重收集 + 全列表重新计算。uni-app 的 Vue 2 内核里,v-for 绑定的 listData.filter(...).map(...) 这类链式调用,会让 Vue 把整个原始数组和所有中间结果(filter 后的新数组、map 后的新数组)都纳入响应式追踪——哪怕你只改了一页数据,它也要为全部 1000 条重新跑一遍 filter 函数。
过滤逻辑必须提前收口,不能留在模板里
模板中写 {{ item.name | formatName }} 或 v-for="item in listData.filter(x => x.status === 'active')" 是性能黑洞。Vue 每次 diff 都要重执行 filter,且无法缓存中间结果。
- 把过滤逻辑移到 data 或 computed 中,且确保 computed 依赖项精简(比如只依赖
this.filterStatus,不依赖整个this.listData) - 如果过滤条件复杂(如多字段搜索),改用方法
getFilteredData(),并在onPullDownRefresh后手动调用,避免自动响应 - 禁止在
v-for内调用带副作用或高开销的函数,例如@click="handle(item)"应改为@click="handle" data-id="{{item.id}}"
关键:分页后过滤必须走服务端,别在前端硬扛
用户下拉刷新时,你以为只是“刷新当前页”,但若你在前端对全量 this.listData 做 .filter(),就等于每次刷新都把几百条数据拉回来再筛一遍——网络 + 计算双重浪费。真机卡顿往往发生在这里。
- 后端接口必须支持过滤参数(如
?status=active&keyword=xxx),前端只传条件,不传原始全量数据 - 前端缓存过滤条件(
this.searchParams),下拉刷新时直接拼进请求 URL,而不是先拉全量再本地 filter - 如果必须前端过滤(如离线场景),至少加节流:用
setTimeout延迟执行,或监听到用户停止输入 300ms 后再更新filteredData
computed 缓存失效是隐形杀手
很多人以为用了 computed 就万事大吉,但只要依赖的数据是响应式对象数组,且数组里每个 item 是深度响应式的(比如含 watch、computed 或嵌套对象),Vue 就会在每次刷新时重建整个依赖图——computed 不仅没提速,反而更慢。
- 过滤后的列表项,尽量用
Object.freeze()包一层(仅限 H5/App;小程序无效但无害) - 避免在
listData里塞computed字段或watch,每个 item 应是纯数据对象 - 检查 Chrome DevTools → Performance 面板,看 “Scripting” 时间是否集中在
render阶段——如果是,大概率是 computed 被反复触发


















