项目中使用到分页的场景很多,例如:后管系统中的表格分页、移动端列表页上拉加载更多。这些场景使用一些分页加载的组件可以实现,但是还是有痛点,每次都得写一套大差不差的逻辑。因此,在此文中我们使用hooks来封装一下通用的逻辑,简化使用。
import { debounce } from 'lodash';
const usePager = (fetch, {
pageSize = 20,
} = {}) => {
const data = reactive({
pageIndex: 1,
pageSize: pageSize,
total: 0,
});
// 刷新函数,增加防抖处理,debounce可以自己实现也可以引入对应库
const refresh = debounce(async () => {
const { pageIndex, pageSize } = data;
const { total, pageIndex: newPageIndex } = await fetch({ pageIndex, pageSize });
// 通常fetch函数只需要返回total即可
data.total = total;
newPageIndex && (data.pageIndex = newPageIndex);
}, 50);
// pageSize改变触发
const handleSizeChange = (pageSize) => {
data.pageIndex = 1;
data.pageSize = pageSize;
refresh();
};
// 页码变化触发
const handleCurrentChange = (pageIndex) => {
data.pageIndex = pageIndex;
refresh();
};
// 此处重置直接重写了pageSize,可根据项目需求修改
const reset = () => {
handleSizeChange(pageSize);
};
refresh();
// 返回分页信息和相关函数
return [data, { handleSizeChange, handleCurrentChange, reset, }];
};
export default usePager;
分页组件的封装,这里基于element。此处没有将usePager和组件写在一起,因为如果换用了UI组件,我们希望分页的逻辑还是可以复用的。
<template>
<el-pagination
:current-page="pageInfo.pageIndex"
:page-sizes="pageSizes"
:page-size="pageInfo.pageSize"
:total="pageInfo.total"
:layout="layout"
v-bind="$attrs"
@size-change="handleSizeChange"
@current-change="handleCurrentChange"
/>
</template>
<script>
import usePager from './usePager';
export default {
props: {
pageSizes: {
type: Array,
default: () => [20, 30, 40, 50]
},
layout: {
type: String,
default: 'total, sizes, prev, pager, next, jumper'
},
fetch: {
type: Function,
required: true,
}
},
setup(props) {
const { fetch } = props;
// 此处未使用到reset
const [ pageInfo, { handleSizeChange, handleCurrentChange }] = usePager(fetch);
return {
pageInfo,
handleSizeChange,
handleCurrentChange
};
},
};
</script>
组件的使用,这里仅展示分页相关的内容
<template>
<div>
<custom-pager :fetch="fetch" />
</div>
</template>
<script>
export default {
setup() {
const tableData = ref([]);
// 自己实现fetch,返回total即可
const fetch = async ({ pageSize, pageIndex }) => {
const { data } = await getData({ pageSize, pageIndex });
tableData.value = data.list;
return { total: tableData.total };
};
return {
tableData,
fetch
};
},
};
</script>