云计算百科
云计算领域专业知识百科平台

打造企业级表格能力:useTable Hook 完整设计解析

前言

在后台管理系统中,表格是最常见的组件之一。一个好的表格 Hook 需要考虑分页、搜索、刷新、数据格式化、状态持久化等方方面面。

最近我分析了一个非常完善的 Vue3 表格 Hook——useTable,它用 200 行代码实现了企业级表格的绝大部分需求。今天就把它的设计精髓分享给大家。

功能概览

useTable 是一个全能型表格数据管理 Hook,提供了以下核心能力:

功能说明
分页管理 自动处理 pageNo/pageSize
数据加载 支持异步接口请求
搜索/刷新 一键触发数据重载
数据格式化 自定义数据转换逻辑
状态持久化 sessionStorage 保存分页状态
并发请求 支持多个接口并行请求
特性数据 支持获取接口返回的额外数据

快速开始

import { useTable } from '@/hooks/useTable'

const {
loading,
data,
pagination,
onSearch,
onRefresh,
loadData
} = useTable({
api: fetchList,
query: getSearchParams, // 搜索参数,支持异步
formatter: formatTableData,
hasPagination: true,
init: true,
key: 'user_list', // 用于状态持久化
})

核心设计解析

1. 状态持久化

最让我眼前一亮的是分页状态的 sessionStorage 持久化设计。这解决了用户在列表页刷新后,分页状态丢失的痛点。

// 从存储加载分页状态
const loadPagination = (key: string): Partial<Pagination> => {
if (!key || typeof sessionStorage === 'undefined') return {}
try {
const stored = sessionStorage.getItem(`table_pagination_${key}`)
return stored ? JSON.parse(stored) : {}
} catch (e) {
return {}
}
}

// 保存分页状态
const savePagination = (key: string, pagination: Pagination) => {
if (!key || typeof sessionStorage === 'undefined') return
sessionStorage.setItem(
`table_pagination_${key}`,
JSON.stringify({ pageNo: pagination.pageNo, pageSize: pagination.pageSize })
)
}

设计亮点:

  • 使用 sessionStorage 而非 localStorage,页面关闭后自动清除,更符合表格场景
  • 异常捕获,保证存储失败不影响主流程
  • 支持多表格隔离,通过 key 参数区分

2. 智能分页处理

删除数据时的分页边界处理,往往是容易被忽略的细节:

async function loadData(checkDataLength: boolean | object = false, pageNo?: number) {
// 批量删除时,直接指定页码
if (pageNo) {
state.pagination.pageNo = pageNo
}
// 当列表只剩1条数据且不是第1页时,自动回退到上一页
else if (typeof checkDataLength === 'boolean' && checkDataLength &&
state.data.length === 1 && state.pagination.pageNo > 1) {
state.pagination.pageNo = state.pagination.pageNo 1
}

// … 发起请求
}

这个 checkDataLength 参数非常巧妙,它让调用者可以控制是否需要这个"智能回退"逻辑。

3. 异步查询参数

支持异步获取查询参数,这是很多 Hook 忽略的点:

const queryBody = query ? await query() : {}
const params = cloneDeep(queryBody)

使用 query 而不是直接传入对象,意味着可以在 query 函数里获取响应式的搜索表单数据:

const searchForm = reactive({ name: '', status: '' })

useTable({
api: fetchList,
query: async () => ({
searchForm
})
})

4. 数据格式化流水线

Hook 提供了两层格式化,职责分离:

// formatterResponse: 格式化接口返回的原始数据
res.data = formatterResponse ? formatterResponse(res.data) : res.data

// formatter: 格式化列表数据
state.data = formatter ? formatter(list || [], result) : list

这种设计非常灵活:

  • formatterResponse 可以处理接口返回结构不标准的情况
  • formatter 可以添加序号、状态标签等业务字段

5. 特性数据获取

接口往往不只是返回列表数据,还会返回统计信息等:

// 调用方定义
useTable({
api: fetchList,
queryFeature: (result) => {
// result 包含接口返回的其他字段
summary.value = result.summary
}
})

// Hook 内部
const { list, total, result } = res?.data || {}
queryFeature && queryFeature(result)

这个设计让表格组件也可以方便地展示汇总数据。

6. 并发请求支持

// 调用方定义
useTable({
api: fetchList,
concurrency: async (params) => {
const [options, categories] = await Promise.all([
fetchOptions(),
fetchCategories()
])
// 处理并发结果
}
})

// Hook 内部
if (concurrency) {
await concurrency(params)
}

这个场景很常见:表格加载时,下拉框选项也需要加载,可以并行请求减少等待时间。

7. 开发环境模拟数据

if (import.meta.env.MODE === 'development') {
defaultData = mockData || []
}

支持在开发阶段传入模拟数据,不用调接口就能预览表格效果。

完整使用示例

<template>
<div>
<!– 搜索表单 –>
<el-form :model="searchForm">
<el-input v-model="searchForm.name" placeholder="请输入姓名" />
<el-button @click="onSearch">搜索</el-button>
</el-form>

<!– 表格 –>
<el-table :data="data" :loading="loading">
<el-table-column prop="name" label="姓名" />
<el-table-column prop="status" label="状态" />
</el-table>

<!– 分页 –>
<el-pagination
v-model:current-page="pagination.pageNo"
v-model:page-size="pagination.pageSize"
:total="pagination.total"
@current-change="loadData()"
/>
</div>
</template>

<script setup>
import { reactive } from 'vue'
import { useTable } from '@/hooks/useTable'

const searchForm = reactive({
name: '',
status: ''
})

const { loading, data, pagination, onSearch, loadData } = useTable({
api: fetchUserList,
query: () => ({ …searchForm }),
key: 'user_management',
formatter: (list) => list.map(item => ({
…item,
statusText: item.status === 1 ? '启用' : '禁用'
})),
queryFeature: (result) => {
console.log('额外数据:', result.extra)
}
})
</script>

优缺点分析

特性评价
✅ 功能全面 分页、搜索、刷新、格式化、持久化一应俱全
✅ 扩展性强 concurrency、queryFeature 等钩子满足复杂场景
✅ 体验优化 智能分页回退、状态持久化
⚠️ 类型安全 部分地方用了 any,可加强
⚠️ 依赖外部 依赖 lodash-es 和 @vueuse/core

总结

useTable 是我见过设计最完善的 Vue3 表格 Hook 之一。它的设计思路值得学习:

  • 配置驱动:通过参数配置决定行为,而不是硬编码
  • 关注点分离:分页、查询、格式化各司其职
  • 细节打磨:智能分页回退、存储异常处理
  • 开放扩展:提供多个钩子点让业务方注入逻辑
  • 如果你正在开发后台管理系统,直接抄这份作业就够了。

    赞(0)
    未经允许不得转载:网硕互联帮助中心 » 打造企业级表格能力:useTable Hook 完整设计解析
    分享到: 更多 (0)

    评论 抢沙发

    评论前必须登录!