Appearance
搜索表单 + 表格
本场景展示如何在后台管理系统中,使用 ProSearchForm 与 ProTable 组件实现数据筛选、分页、CRUD 等典型业务需求。
业务场景
- 顶部为筛选条件输入区(搜索表单)
- 下方为数据表格展示区
- 支持搜索、重置、批量操作、导出等功能
- 适用于用户管理、订单管理、数据分析等后台页面
基础示例
适合简单场景,不使用 useList,仅演示表单与表格联动。
推荐场景:useList Hook + 组件组合
推荐用法,自动管理分页、筛选、重置、加载态,模拟真实业务数据。
分页逻辑详解
✅ useList 自动分页机制
useList Hook 内部实现了完整的分页自动化:
typescript
// useList 内部实现
watch([curPage, pageSize], async () => {
await loadData(curPage.value) // 页码或页大小变化时自动重新加载
})这意味着:
- ✅ 改变
curPage.value→ 自动加载新页数据 - ✅ 改变
pageSize.value→ 自动重新加载 - ✅ 无需手动调用
loadData()
📊 分页事件处理流程
1. 页码切换
typescript
function handlePageChange(page, size) {
curPage.value = page
// ✅ useList 的 watch 检测到 curPage 变化
// ✅ 自动调用 loadData(page)
// ✅ 请求参数: { pageNum: page, pageSize, ...searchForm }
}2. 页大小改变
typescript
function handleSizeChange(current, size) {
pageSize.value = size
curPage.value = 1 // 重要:改变页大小时重置到第一页
// ✅ useList 的 watch 检测到变化
// ✅ 自动调用 loadData(1)
}3. 搜索筛选
typescript
// ProSearchForm 的 submit 事件
@submit="loadData"
// 点击搜索按钮
→ 触发 loadData()
→ 保持当前页码和页大小
→ 请求参数: { pageNum: curPage.value, pageSize.value, ...searchForm.value }4. 重置筛选
typescript
async function handleReset() {
curPage.value = 1 // 重置到第一页
await reset() // useList 的 reset 方法
// ✅ reset() 内部会清空 filters.state 并调用 loadData()
}5. 删除后的智能分页
typescript
async function handleDelete(record) {
// ... 删除逻辑 ...
// 如果当前页只有这一条数据,且不是第一页
if (dataSource.value.length === 1 && curPage.value > 1) {
curPage.value = curPage.value - 1 // 跳转到上一页
} else {
await loadData() // 重新加载当前页
}
}🔄 完整的分页流程图
用户操作
↓
┌──────────────────────────────────┐
│ 1. 点击页码 (第 3 页) │
│ → handlePageChange(3, 10) │
│ → curPage.value = 3 │
└──────────────────────────────────┘
↓
┌──────────────────────────────────┐
│ 2. useList 的 watch 检测到变化 │
│ → watch([curPage, pageSize]) │
│ → 触发 loadData(3) │
└──────────────────────────────────┘
↓
┌──────────────────────────────────┐
│ 3. loadData 构造请求参数 │
│ → params = { │
│ pageNum: 3, │
│ pageSize: 10, │
│ name: searchForm.name │
│ } │
└──────────────────────────────────┘
↓
┌──────────────────────────────────┐
│ 4. 调用 request(params) │
│ → fetch API │
│ → 返回第 3 页数据 │
└──────────────────────────────────┘
↓
┌──────────────────────────────────┐
│ 5. useList 自动更新状态 │
│ → dataSource.value = 新数据 │
│ → total.value = 总数 │
│ → loading.value = false │
└──────────────────────────────────┘
↓
表格显示第 3 页数据 ✅关键点总结
✅ useList 的强大之处
自动分页监听
watch([curPage, pageSize])自动监听变化- 无需手动绑定事件
- 修改页码/页大小即可触发加载
参数自动合并
typescript{ pageNum, pageSize, ...filters.state.value } // 自动合并筛选条件和分页参数智能状态管理
loading自动管理dataSource自动更新total自动同步
✅ 分页事件绑定
vue
<ProTable
:columns="columns"
:dataSource="dataSource"
:loading="loading"
:pagination="{
current: curPage, // ✅ 绑定当前页
pageSize: pageSize, // ✅ 绑定页大小
total: total, // ✅ 绑定总数
onChange: handlePageChange, // ✅ 页码变化事件
onShowSizeChange: handleSizeChange // ✅ 页大小变化事件
}"
/>✅ 智能页码处理
场景 1: 删除当前页最后一条
typescript
if (dataSource.value.length === 1 && curPage.value > 1) {
curPage.value = curPage.value - 1 // 跳转到上一页
}场景 2: 搜索后重置页码
typescript
// 搜索时保持当前页码,但如果结果少于当前页,会自动调整
@submit="loadData" // 不改变 curPage场景 3: 重置时回到第一页
typescript
async function handleReset() {
curPage.value = 1
await reset()
}扩展建议
1. 记住用户的分页偏好
typescript
import { useLocalStorage } from '@vueuse/core'
const pageSize = useLocalStorage('user-list-page-size', 10)
// 用户选择的页大小会被记住2. URL 同步分页状态
typescript
import { useRoute, useRouter } from 'vue-router'
const route = useRoute()
const curPage = ref(Number(route.query.page) || 1)
watch(curPage, (newPage) => {
router.replace({ query: { ...route.query, page: newPage } })
})
// 页码会反映在 URL 中,支持刷新保持状态3. 虚拟滚动优化大数据
typescript
// 当数据量巨大时(10000+ 条)
// 考虑使用虚拟滚动替代传统分页