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进行扩展和优化。

相关推荐
Json_181790144805 分钟前
电商拍立淘按图搜索API接口系列,文档说明参考
前端·数据库
风尚云网28 分钟前
风尚云网前端学习:一个简易前端新手友好的HTML5页面布局与样式设计
前端·css·学习·html·html5·风尚云网
木子020431 分钟前
前端VUE项目启动方式
前端·javascript·vue.js
GISer_Jing33 分钟前
React核心功能详解(一)
前端·react.js·前端框架
捂月36 分钟前
Spring Boot 深度解析:快速构建高效、现代化的 Web 应用程序
前端·spring boot·后端
深度混淆43 分钟前
实用功能,觊觎(Edge)浏览器的内置截(长)图功能
前端·edge
Smartdaili China44 分钟前
如何在 Microsoft Edge 中设置代理: 快速而简单的方法
前端·爬虫·安全·microsoft·edge·社交·动态住宅代理
秦老师Q1 小时前
「Chromeg谷歌浏览器/Edge浏览器」篡改猴Tempermongkey插件的安装与使用
前端·chrome·edge
滴水可藏海1 小时前
Chrome离线安装包下载
前端·chrome
m51271 小时前
LinuxC语言
java·服务器·前端