useList-通用列表管理hook

作者:袖梨 2026-05-28

本文详细介绍useList通用hook,该工具能高效管理列表数据加载、分页和筛选功能,提升开发效率。

useList 通用列表管理hook

概述

通过useList.hook.ts可实现列表数据的统一管理,包含加载状态、分页控制及筛选功能。

useList 通用列表管理hook

核心功能

  1. 响应式状态管理:采用reactive管理筛选条件和分页配置
  2. 数据请求处理:统一封装loading状态、错误捕获和数据赋值逻辑
  3. 加载模式切换:通过isPush参数支持普通分页与滚动加载两种场景
  4. 条件重置:保存初始筛选值,提供一键重置功能

详细代码

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,
  }
}

类型定义

IPage

分页参数接口定义:

interface IPage {
  pageNum: number // 当前页码
  pageSize: number // 每页条数
  total?: number // 总条数(响应数据填充)
}

GetListFnArgsType

列表请求参数类型规范:

interface GetListFnArgsType {
  pagination: IPage // 分页信息
  filter: T // 筛选条件
}

返回值

属性类型说明
listRef>列表数据
loadingRef加载状态
filterReactive筛选条件(响应式)
paginationReactive分页信息(响应式)
loadData(curPage?: number, isPush?: boolean) => Promise加载数据
loadDataPage(page: number, isPush?: boolean) => Promise分页加载
loadDataPageSize(pageSize: number) => void改变每页条数
filterReset() => void重置筛选条件
filterSearch() => Promise搜索(重置页码为1)

方法详解

loadData(curPage, isPush)

核心数据加载方法:

  • curPage: 指定当前页码,默认使用pagination.pageNum
  • isPush: 控制数据追加方式,true为追加模式,false为替换模式

loadDataPage(page, isPush)

分页加载方法,内部调用loadData实现。

loadDataPageSize(pageSize)

调整每页显示条数并重新加载数据。

filterReset()

将筛选条件恢复初始值,并重新请求第一页数据。

filterSearch()

执行搜索操作,自动重置页码后加载数据。

使用示例

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通过封装核心列表操作逻辑,大幅简化了前端列表功能的开发流程,是提升开发效率的利器。

相关文章

精彩推荐