filter()不可直接用于v-for,否则引发全量遍历与重复Proxy代理;应通过computed缓存过滤结果,配合watch防抖、后端分页过滤及虚拟滚动优化性能。

uni-app里filter()函数不能用在v-for里做实时过滤
直接在v-for中调用filter()(比如v-for="item in list.filter(x => x.status === 'active')")会导致每次渲染都执行全量遍历,且Vue会为整个过滤后的新数组创建全新响应式代理——哪怕只改一个字段,也会触发1000次依赖收集。这不是“慢一点”,而是让list里每个对象都额外套一层Proxy,内存和CPU双爆炸。
常见错误现象:setData耗时陡增、滚动卡顿、真机内存飙升、iOS端白屏。
- 过滤逻辑必须提前计算好,存进单独的
computed或data字段,而不是写在模板里 - 如果过滤条件会频繁变动(如搜索框输入),要用
watch监听关键词,手动更新过滤后数组,避免响应式链路过长 - 禁止在
filter()回调里访问this.xxx或调用方法——这会让Vue无法缓存结果,每次重跑
用computed缓存过滤结果比methods更安全
computed有缓存机制,只要依赖不变就不会重复执行;而methods每次渲染都调用,等于把filter()塞进render函数里白跑一遍。尤其当列表项含图片、复杂组件时,这个开销会被放大数倍。
使用场景:筛选状态、分类标签、搜索关键词匹配。
- 写法示例:
computed: { filteredList() { return this.rawList.filter(item => item.name.includes(this.searchKey)); } } - 注意
searchKey必须是响应式数据,否则computed不触发更新 - 若
rawList本身很大(>500项),建议配合防抖:输入停顿300ms后再更新searchKey,避免边输边筛
后端过滤比前端filter()更彻底
前端filter()只是“藏起来”,数据还在内存里。真正要减负,得让后端按条件返回子集。比如用户点“待发货”,就该请求/orders?status=pending,而不是拉回全部订单再筛。
性能影响很直接:减少传输体积、降低JS解析压力、避免无用数据进入响应式系统。
- 接口必须支持查询参数(
status、category、keyword等),不能只靠page/pageSize - 前端要做兜底:如果后端没返回
total,就别显示“共XX条”,防止用户误以为数据不全 - 搜索场景下,若后端支持模糊匹配,就别在前端用
includes()——字符串匹配交给数据库更稳
filter() + 虚拟列表才是完整解法
很多人以为“加个filter就完了”,但漏了关键点:过滤后的数组如果仍有上千项,v-for照样卡。filter只是第一步,后面必须接虚拟滚动,否则只是把问题从“全量渲染”挪到“全量过滤后渲染”。
容易被忽略的地方:你改了searchKey,computed更新了filteredList,但<list-view :items="filteredList"></list-view>没重置滚动位置,用户会看到空白区——因为list-view内部缓存的scrollTop还指着旧列表的偏移量。
- 每次
filteredList长度变化较大时(比如从1000→20),手动调用scrollTo(0, 0)重置位置 - 如果用
scroll-view手写虚拟列表,estimatedItemSize要随过滤结果动态调整,否则缓冲区计算失准 -
filter()后别直接赋值给v-for源数组,保持原始数据干净,方便后续切回“全部”状态



















