Vue3开发一个用于分页的 `usePage` hook

前言

在开发中我们经常会遇到分页的需求,为此我们可能会写很多关于加载状态、页码增加减少、数据获取等等逻辑。在实际的项目中往往有很多需要分页的功能,这个时候我们就需要将逻辑抽取出来进行封装。

在vue3中我们就可以开发一个分页的hook,接下来我将会分享怎么开发一个简单的分页hook。

准备工作:模拟分页数据

首先,我们需要一个模拟分页数据的方法。在项目中,分页数据的格式通常是标准化的。我们将创建一个mockPage方法来模拟数据获取。

新建service/mock.ts

js 复制代码
export function mockPage({ page = 1, pageSize = 10 }) {
  return new Promise((resolve) => {
    let list = []
    for (let i = 0; i < pageSize; i++) {
      let id = (page - 1) * pageSize + i + 1
      list.push({
        id: id,
        name: `name-${id}`,
      })
    }
    setTimeout(() => {
      resolve({
        pagination: {
          pageSize: pageSize,
          page: page,
          total: 30,
        },
        list: list
      })
    }, 1000)
  })
}

封装 usePage Hook

hooks/page.ts 中,我们定义了一个名为 usePage 的组合式API,用于封装所有与分页相关的逻辑。

js 复制代码
import { reactive, ref } from "vue"
type LoadingStatus = 'loading' | 'loadmore' | 'nomore'; // 加载状态 loading-加载中 loadmore-加载更多 nomore-没有更多数据

interface Res {
  list: any[];
  pagination: {
    page: number;
    pageSize: number;
    total: number;
  }
}
export function usePage(refresh: (params: any) => void) {
  // 初始化当前页列表数据和加载状态
  const list = ref<any>([]); // 当前页列表数据
  const loadingStatus = ref<LoadingStatus>('loading');

  const pagination = reactive({
    page: 1,
    pageSize: 10,
    total: 0
  })

  const isLoading = () => loadingStatus.value === 'loading';

/**
 * 执行数据获取操作,并处理获取后的数据和状态更新。
 * @param fetch 一个接受参数并返回Promise的函数,用于执行数据获取操作。
 * @param params 传递给fetch函数的参数对象。
 * @returns 返回一个对象,包含一个用于结束加载状态的done函数和当前传递给fetch函数的参数数据。
 */
function onFetch(fetch: (params: any) => Promise<any>, params: any) {
  // 合并分页信息和传入的参数
  const data = {
    ...pagination,
    ...params
  }
  loadingStatus.value = 'loading'; // 更新加载状态为"loading"
  // 执行数据获取,更新列表和分页信息,根据返回结果控制加载状态
  fetch(data).then((res: Res) => {
    list.value = res.list
    // 更新分页信息
    Object.assign(pagination, res.pagination)
    // 根据返回数据的总数和当前页数判断是否已完成加载
    done(res.pagination.total <= res.pagination.page * res.pagination.pageSize)
  }).catch((error) => {
    console.error("Fetching data failed:", error);
    loadingStatus.value = 'nomore';
    // 在此处根据实际情况处理错误,例如设置错误信息或重试逻辑
  });

  /**
   * 结束请求
   * 根据传入的isFinish参数决定是结束加载(设置为'nomore')还是继续加载(设置为'loadmore')。
   * @param isFinish 指示是否完成加载的布尔值。如果为true,则将加载状态设置为'nomore';如果为false,则设置为'loadmore'。
   *                 此参数为可选,默认为false。
   */
  function done(isFinish?: boolean) {
    // 更新加载状态
    loadingStatus.value = isFinish ? 'nomore' : 'loadmore';
  }

  return {
    done,
    data
  }
}

  /**
   * 用于加载写一页数据
   * 当当前加载状态为"loadmore"时,更新状态为"loading",增加页码,并触发刷新操作。
   * 注意:此函数不接受参数,也不返回任何值。
   */
  function loadNext() {
    // 当加载状态为"loadmore"时,进行加载更多数据的操作
    if (loadingStatus.value === 'loadmore') {
      pagination.page++; // 增加当前页码
      refresh({
        page: pagination.page // 刷新数据,使用新的页码
      })
    }
  }

  /**
   * 加载上一页数据
   */
  function loadPrev() {
    if (pagination.page > 1) {
      pagination.page--;
      refresh({
        page: pagination.page
      })
    }
  }

  return {
    list: list,
    loadingStatus: loadingStatus,
    pagination,
    onFetch,
    loadNext,
    loadPrev,
    isLoading
  }
}

实现分页测试页面 index.vue

使用 usePage Hook,我们可以方便地在 index.vue 组件中实现用户界面的分页功能。

html 复制代码
<template>
  <div class="page--use-page">
    <div v-for="(item, index) in list" :key="index">{{ item }}</div>
    <button @click="loadPrev">上一页</button>
    <button @click="loadNext">下一页</button>
    <div>{{ loadingStatus }}</div>
    <div>{{ pagination }}</div>
  </div>
</template>
<script setup lang="ts">
import { usePage } from './hooks/page';
import { mockPage } from './service/mock'

const { list, loadingStatus, onFetch, loadNext, loadPrev, pagination } = usePage(refresh)

refresh()

function refresh(params?: any) {
  onFetch(mockPage, params)
}

</script>

到这里一个简单的分页方法usePage就完成了,下面是运行效果。

效果展示

点击下一页

通过封装usePageHook,在Vue3中实现分页功能变得非常简单和直观。这种方法不仅提高了代码的可维护性和复用性,也让分页逻辑的管理更加清晰。在项目中可以根据实际的需求对usePage进行扩展和优化。

相关推荐
web1478621072330 分钟前
C# .Net Web 路由相关配置
前端·c#·.net
m0_7482478031 分钟前
Flutter Intl包使用指南:实现国际化和本地化
前端·javascript·flutter
飞的肖34 分钟前
前端使用 Element Plus架构vue3.0实现图片拖拉拽,后等比压缩,上传到Spring Boot后端
前端·spring boot·架构
青灯文案142 分钟前
前端 HTTP 请求由 Nginx 反向代理和 API 网关到后端服务的流程
前端·nginx·http
m0_748254881 小时前
DataX3.0+DataX-Web部署分布式可视化ETL系统
前端·分布式·etl
ZJ_.1 小时前
WPSJS:让 WPS 办公与 JavaScript 完美联动
开发语言·前端·javascript·vscode·ecmascript·wps
GIS开发特训营1 小时前
Vue零基础教程|从前端框架到GIS开发系列课程(七)响应式系统介绍
前端·vue.js·前端框架·gis开发·webgis·三维gis
Cachel wood1 小时前
python round四舍五入和decimal库精确四舍五入
java·linux·前端·数据库·vue.js·python·前端框架
学代码的小前端1 小时前
0基础学前端-----CSS DAY9
前端·css
joan_852 小时前
layui表格templet图片渲染--模板字符串和字符串拼接
前端·javascript·layui