Skip to content

搜索表单 + 表格

本场景展示如何在后台管理系统中,使用 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 的强大之处

  1. 自动分页监听

    • watch([curPage, pageSize]) 自动监听变化
    • 无需手动绑定事件
    • 修改页码/页大小即可触发加载
  2. 参数自动合并

    typescript
    { pageNum, pageSize, ...filters.state.value }
    // 自动合并筛选条件和分页参数
  3. 智能状态管理

    • 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+ 条)
// 考虑使用虚拟滚动替代传统分页

相关文档