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

相关推荐
名字还没想好☜7 分钟前
React 实现暗黑模式切换:localStorage 持久化、SSR 首屏闪烁与跟随系统主题
前端·javascript·react.js·ecmascript·react·next.js
console.log('npc')1 小时前
Git 冲突与 AI 协助指南
前端·人工智能·git·大模型
爱学堂IT分享2 小时前
Cesium可视化系统实战课程-Cesium教程学习
前端
糖墨夕3 小时前
理解大语言模型:Agent 的“大脑”
前端·agent
Rain的Java大神之路3 小时前
JavaWeb开发如何解决跨域问题
java·前端·后端·nginx·web安全·面试·运维开发
cpolar技术支持3 小时前
浏览器也能跑本地 AI:用 Transformers.js + WebGPU 做一个最小推理 Demo,cpolar 给同事远程体验
前端·ai·cpolar·webgpu·transformers.js
计算机毕设定制辅导-无忧学长3 小时前
《基于SpringBoot青年公寓出租管理系统的设计与实现》
java·vue.js·spring boot·青年公寓出租管理系统
计算机魔术师5 小时前
OpenAI 发布 GPT-6 Astra:多项基准刷新纪录, cybersecurity 能力达 Critical 阈值
前端
xy34535 小时前
Axure9.0中继器遮罩实现方法
前端·ui·html·axure·原型·产品设计
风骏时光牛马5 小时前
智能任务自动化协同AI工作流
前端