前言
在开发中我们经常会遇到分页的需求,为此我们可能会写很多关于加载状态、页码增加减少、数据获取等等逻辑。在实际的项目中往往有很多需要分页的功能,这个时候我们就需要将逻辑抽取出来进行封装。
在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就完成了,下面是运行效果。
效果展示
点击下一页
通过封装usePage
Hook,在Vue3中实现分页功能变得非常简单和直观。这种方法不仅提高了代码的可维护性和复用性,也让分页逻辑的管理更加清晰。在项目中可以根据实际的需求对usePage进行扩展和优化。