这是一份脱离具体业务项目也能看的学习资料。
目标:学会把一个"可查询、可分页、可渲染"的列表,按清晰的数据流搭起来。
1. 入门:先搞懂 ref 是怎么赋值的
ts
import { ref } from 'vue'
type User = {
id: number
name: string
}
const users = ref<User[]>([])
users.value = [
{ id: 1, name: 'Alice' },
{ id: 2, name: 'Bob' }
]
关键点:
ref包裹后的值要通过.value读写- 给数组赋值时,直接替换新数组最直观
2. 入门:把数据渲染出来
vue
<template>
<view v-for="user in users" :key="user.id">
{{ user.name }}
</view>
</template>
这一步只有一个目标:先通路,别一上来就加筛选、分页、排序。
3. 进阶第一步:建立"三层数据"
很多人后期越改越乱,是因为把所有逻辑都操作同一个数组。
建议从一开始就拆三层:
ts
const sourceData = ref<User[]>([]) // 源数据层(永远保留)
const filteredData = ref<User[]>([]) // 结果层(筛选后)
const visibleData = computed(() => // 展示层(分页后)
filteredData.value.slice(0, visibleCount.value)
)
这就是最核心的数据流:
sourceData -> filteredData -> visibleData -> UI
4. 查询筛选:永远基于源数据
ts
const keyword = ref('')
function doSearch() {
const kw = keyword.value.trim().toLowerCase()
filteredData.value = sourceData.value.filter(item =>
!kw || item.name.toLowerCase().includes(kw)
)
visibleCount.value = pageSize
}
为什么这么做:
- 不会出现"筛选一次后源数据丢失"
- 清空条件可直接回到全量
- 逻辑稳定,容易测
5. 分页:只改窗口,不改结果集
ts
const pageSize = 10
const visibleCount = ref(pageSize)
function loadMore() {
visibleCount.value = Math.min(
visibleCount.value + pageSize,
filteredData.value.length
)
}
思想:分页是"显示多少条",不是"删掉后面的数据"。
6. 初始化流程(标准模板)
ts
async function init() {
// 1) 拉取源数据
sourceData.value = await fetchList()
// 2) 初始化筛选结果(通常等于全量)
filteredData.value = [...sourceData.value]
// 3) 初始化分页窗口
visibleCount.value = pageSize
}
这三步顺序尽量固定,团队协作时非常省心。
7. 常见坑(高频)
坑 1:直接改 sourceData
错误示例:
ts
sourceData.value = sourceData.value.filter(...)
后果:你把"原件"改没了,清空筛选很难恢复。
坑 2:查询后忘了重置分页
如果不重置 visibleCount,会出现:
- 新结果很少,但页面还按旧窗口显示逻辑跑
- 滚动状态、空态表现异常
坑 3:key 不稳定
v-for 尽量用业务唯一 id,不要用下标。
8. 命名建议(可直接套用)
sourceData:全量源数据filteredData:当前条件结果visibleData:当前页可见数据visibleCount:当前可见条数pageSize:每页大小
比起 list1/list2/list3,这种命名更容易维护。
9. 一个最小可运行思路
ts
const sourceData = ref<Item[]>([])
const filteredData = ref<Item[]>([])
const pageSize = 10
const visibleCount = ref(pageSize)
const visibleData = computed(() =>
filteredData.value.slice(0, visibleCount.value)
)
function resetFilter() {
filteredData.value = [...sourceData.value]
visibleCount.value = pageSize
}
只要你先把这个骨架搭好,后续加排序、多条件筛选、远程分页都不会乱。
10. 从入门到进阶的学习路线
- 入门 :掌握
ref/.value/v-for - 基础工程化:把列表拆成三层数据
- 交互完善:加搜索 + 重置 + 触底加载
- 进阶:加入排序、组合筛选、缓存查询条件
- 高级 :接入后端分页和防抖搜索 : 进阶文档
11. 一句话总结
列表页稳定的核心不是"某个 API",而是数据分层思想:
源数据不动,结果数据承接条件,展示数据只负责窗口。