本文详细介绍useList通用hook,该工具能高效管理列表数据加载、分页和筛选功能,提升开发效率。
通过useList.hook.ts可实现列表数据的统一管理,包含加载状态、分页控制及筛选功能。

reactive管理筛选条件和分页配置isPush参数支持普通分页与滚动加载两种场景import { reactive, ref, toRaw } from 'vue'export interface IPage {
pageNum: number
pageSize: number
total?: number
}export interface GetListFnArgsType {
pagination: IPage
filter: T
}
export default function useListextends Record<string, any>>(
filterOption: U,
getListFn: (args: GetListFnArgsType) => Promise<InResult<{ records: Array, total: number }>>, // InResult 类型定义请阅读uni.request 二次封装这篇文章
pageOption?: IPage,
) {
const list = ref<Array>([])
const loading = ref(false)
const filter = reactive({ ...filterOption })
const pagination = reactive<IPage>({
...pageOption,
pageSize: pageOption?.pageSize || 10,
pageNum: pageOption?.pageNum || 1,
}) // 请求列表数据
const loadData = async (curPage = pagination.pageNum, isPush = true) => {
pagination.pageNum = curPage
loading.value = true const req = { pagination, filter: toRaw(filter) as U }
try {
const res = await getListFn(req as GetListFnArgsType)
loading.value = false
if (!isPush) {
list.value = res.data.records as Array<any>
}
else {
list.value = [...list.value, ...res.data.records as Array<any>]
}
pagination.total = res.data.total
}
catch (error) {
loading.value = false
console.log(error)
}
} // 重置筛选
const filterReset = () => {
Object.assign(filter, filterOption)
loadData(1, false)
} // 搜索
const filterSearch = () => {
console.log(121212)
return loadData(1, false)
} // 分页请求
const loadDataPage = (page: number, isPush = true) => {
return loadData(page, isPush)
} // 分页大小改变
const loadDataPageSize = (pageSize: number) => {
pagination.pageSize = pageSize
loadData(1, false)
} return {
list,
loading,
filter,
pagination,
loadData,
loadDataPage,
loadDataPageSize,
filterReset,
filterSearch,
}
}
分页参数接口定义:
interface IPage {
pageNum: number // 当前页码
pageSize: number // 每页条数
total?: number // 总条数(响应数据填充)
}
列表请求参数类型规范:
interface GetListFnArgsType {
pagination: IPage // 分页信息
filter: T // 筛选条件
}
| 属性 | 类型 | 说明 |
|---|---|---|
list | Ref> | 列表数据 |
loading | Ref | 加载状态 |
filter | Reactive | 筛选条件(响应式) |
pagination | Reactive | 分页信息(响应式) |
loadData | (curPage?: number, isPush?: boolean) => Promise | 加载数据 |
loadDataPage | (page: number, isPush?: boolean) => Promise | 分页加载 |
loadDataPageSize | (pageSize: number) => void | 改变每页条数 |
filterReset | () => void | 重置筛选条件 |
filterSearch | () => Promise | 搜索(重置页码为1) |
核心数据加载方法:
pagination.pageNumtrue为追加模式,false为替换模式分页加载方法,内部调用loadData实现。
调整每页显示条数并重新加载数据。
将筛选条件恢复初始值,并重新请求第一页数据。
执行搜索操作,自动重置页码后加载数据。
import type { IEvent } from '@/api/task/type'
import { getEventList } from '@/api/task'
import useList, { type GetListFnArgsType } from '@/hooks/uesList.hook'const filterOption = {
keyword: '',
status: '',
startTime: '',
endTime: '',
}async function getListData(params: GetListFnArgsType<typeof filterOption>) {
const { pagination, filter } = params
const req = {
params: {
pageNo: pagination.pageNum,
pageSize: pagination.pageSize,
},
data: {
startTime: filter.startTime,
endTime: filter.endTime,
},
} const res = await getEventList(req)
return res /**
* 这里假设接口返回的数据格式不是 records 和 total
* 你可以在 getListData 中根据实际情况调整 records 和 total 的赋值,如:
* const res = await getEventList(req);
* return {data: { records: res.data.list, total: res.data.totalSize }}
*/
}const { list, filter, pagination, filterSearch, loadDataPage } = useList<IEvent, typeof filterOption>(filterOption, getListData, { pageNum: 1, pageSize: 20 })
<template>
<cus-list v-model:keyword="filter.keyword" :refresh-func="filterSearch" :load-func="loadDataPage" :pagination="pagination" @search="filterSearch" @clear="filterSearch">
<template #serach-left>
<van-dropdown-menu style="--dropdown-menu-title-active-text-color: var(--uni-color-primary);--dropdown-menu-background-color: transparent;--dropdown-menu-title-text-color: var(--uni-text-color); --dropdown-menu-option-active-color: var(--uni-color-primary)" custom-class="min-w-[100rpx]">
<van-dropdown-item v-model:value="filter.siteId" :options="siteIdOptions" @change="onSiteChange" />
van-dropdown-menu>
template> <template #search-filter="{ data }">
<view class="box-border h-full w-full p-2">
<view class="flex items-center gap-2">
<view>开始时间:view>
<cus-date-picker v-model="filter.startTime" type="date" />
view>
<view class="mt-2 flex items-center gap-2">
<view>结束时间:view>
<cus-date-picker v-model="filter.endTime" type="date" />
view>
<view class="mt-5 flex gap-2">
<van-button size="small" block class="flex-1" @click="onFilterReset(data)">
重置
van-button>
<van-button type="primary" block size="small" class="flex-1" @click="onFilter(data)">
确定
van-button>
view>
view>
template> <template #default>
<task-item v-for="item in list" :key="item.id" :record="item" />
template>
cus-list>
template>
useList hook通过封装核心列表操作逻辑,大幅简化了前端列表功能的开发流程,是提升开发效率的利器。