uni-list 本身不支持内置过滤器,需通过 computed 或 methods 预处理数据后再渲染;直接在 v-for 中使用管道符会报错,因 vue 3 已移除该语法;应避免在模板中实时过滤,而应在响应式依赖下用 computed 实现搜索与分类双条件过滤,并配合节流、分页及服务端过滤以保障性能。

uni-list 本身不支持内置过滤器,得靠 computed 或 methods 处理数据
uni-list 只是渲染容器,它不提供筛选逻辑。所谓“在 uni-list 中用过滤器”,实际是指:先对 rawList 做过滤,再把结果传给 uni-list-item 渲染。直接在模板里对 uni-list 加 | filterName 是无效的——它不是 Vue 的普通组件,不能被管道符处理。
常见错误是写成这样:<uni-list><uni-list-item v-for="item in list | myFilter" :key="item.id"></uni-list-item></uni-list>
这会报错或静默失败,因为 v-for 不支持带管道符的表达式(Vue 3 已移除该语法,uni-app 3.x 基于 Vue 3)。
- 正确做法是把过滤逻辑提前到 data 或 computed 中
- 若用
computed,注意响应式依赖要完整(比如搜索关键词、分类 ID、排序字段都得是响应式变量) - 避免在
v-for内做filter()或sort(),否则每次重绘都执行,大数据量时卡顿明显
用 computed 实现搜索 + 分类双条件过滤
适合中等数据量(
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 过滤,而不是靠属性“假装隐藏”。










