uni-list 组件本身并不支持内置过滤器,通常需要先通过 computed 计算属性或 methods 方法对数据进行预处理后再渲染;如果直接在 v-for 中使用管道符,不仅无法生效,还会报错,因为 Vue 3 已经移除了过滤器语法;更推荐的做法是避免在模板里实时执行过滤,而是在响应式依赖基础上通过 computed 实现搜索与分类的双条件筛选,并结合节流、分页以及服务端过滤策略来保证列表渲染性能。

uni-list 本身不支持内置过滤器,需要借助 computed 或 methods 先处理数据
uni-list 只是一个列表渲染容器,自身并不具备数据筛选能力。很多人所说的“在 uni-list 中使用过滤器”,本质上其实是:先对rawList进行筛选处理,再把过滤后的结果交给uni-list-item渲染。若直接在模板里给uni-list或 v-for 表达式加上| filterName,通常是无效的,因为这不是 Vue 2 时代可用的常规写法,而且 Vue 3 已不再支持这种管道过滤器语法。
常见的错误示例写法如下:
这种写法往往会直接报错,或者出现静默失效的情况,根本原因在于 v-for 不支持包含管道符的表达式(Vue 3 已移除此语法,而 uni-app 3.x 正是基于 Vue 3 构建的)。
- 正确方式是把过滤逻辑提前放到 data、methods 或 computed 中处理
- 如果使用
computed,要确保响应式依赖完整,例如搜索关键词、分类 ID、排序字段等都必须是响应式变量 - 不要在
v-for中直接执行filter()或sort(),否则每次渲染都会重复计算,数据量一大就容易明显卡顿
使用 computed 实现搜索 + 分类双条件过滤
这种方式比较适合中等规模的数据列表(<1000 条),逻辑更清晰,维护起来也更方便。同时要注意空值判断以及字符串大小写统一处理,避免筛选结果不准确。
computed: {
filteredList() {
let list = this.rawList || []
// 搜索关键词
if (this.searchKey) {
const key = this.searchKey.trim().toLowerCase()
list = list.filter(item =>
item.title?.toLowerCase().includes(key) ||
item.desc?.toLowerCase().includes(key) ||
item.tag?.toLowerCase().includes(key)
)
}
// 分类筛选(假设后端返回 category 字段)
if (this.selectedCategory !== '') {
list = list.filter(item => item.category === this.selectedCategory)
}
return list
}
}
this.rawList是原始数据源,建议始终保持不变,不要在过滤过程中直接修改this.searchKey和this.selectedCategory必须在data()中声明,否则 computed 无法正确响应更新- 字符串比较前统一转成小写,可以避免 “Apple” 和 “apple” 因大小写不同而匹配失败
- 使用
item?.title这类可选链写法可以防止空字段报错,相比item.title && item.title.includes(...)更简洁直观
大数据量(>1000 条)必须结合节流和分页,不能只依赖前端过滤
如果完全依靠前端去过滤 2000 条以上的数据,首次渲染很可能出现 300ms 以上的卡顿,滚动时还可能伴随掉帧。虽然 uni-app 的 uni-list 支持虚拟列表思路,但前提依然是传入的数据量不能失控。
- 优先考虑服务端分页:把
searchKey、category等筛选参数传给后端,由数据库先完成过滤,再返回当前页数据 - 前端要做节流或防抖:用户每输入一个字符时,可延迟 300ms 再触发
filteredList重新计算,减少高频更新 - 输入框绑定
@input时,不要直接调用filter(),建议使用setTimeout或lodash.debounce做优化 - 如果仍然坚持全量加载后再做前端筛选,至少要加上 loading 提示,避免用户误以为页面卡死或程序无响应
不要把过滤逻辑和 uni-list-item 的内置属性混为一谈
uni-list-item 的 disabled、show-badge、rightText 这些属性本质上都是用于控制 UI 展示状态的,并不是数据过滤开关。有些开发者会尝试用 :disabled="!item.match" 来“隐藏”不符合条件的项,这种做法其实并不正确:
- DOM 节点依然存在,只是视觉上变灰,仍会占用布局空间,对滚动性能没有实际改善
- 无障碍阅读器仍可能读取这些 disabled 项,语义上并不合理
rightText本身不支持溢出隐藏,文本过长时可能撑开宽度,影响整个列表的整齐性
真正需要隐藏列表项时,应当从数据源层面直接剔除不匹配的数据,也就是通过 computed 或 methods 先完成过滤,而不是依赖组件属性去“伪隐藏”。
