import { reactive, ref, watch } from 'vue'
export type Pagination = {
currentPage: number
pageSize: number
total: number
}
/**
* 简化表格和分页
* @example
* ```js
* const { data, loading, pagination, error } = usePagniation(getData)
* ```
* ```html
* <ElPagination v-bind="page" />
* ```
*/
export function usePagniation<T extends { total: number; list: any[] }>(
getData: (pagination: Pick<Pagination, 'currentPage' | 'pageSize'>) => Promise<T> | T,
config?: { defaultPage?: number; defaultPageSize?: number },
) {
const { defaultPage = 1, defaultPageSize = 10 } = config ?? {}
const data = ref([] as T['list'])
const loading = ref(true)
const error = ref<null | unknown>(null)
const pagination = reactive<
Pagination & {
'onUpdate:currentPage': (val: number) => void
'onUpdate:pageSize': (val: number) => void
}
>({
currentPage: defaultPage,
pageSize: defaultPageSize,
total: 0,
'onUpdate:currentPage': (val) => {
pagination.currentPage = val
},
'onUpdate:pageSize': (val) => {
pagination.pageSize = val
},
})
let key = 0
async function _loadData(currentPage: number, pageSize: number) {
++key
const currentKey = key
loading.value = true
error.value = null
try {
const res = await getData({
currentPage,
pageSize,
})
if (key !== currentKey) return
const { list, total } = res
data.value = list
pagination.total = total
} catch (e) {
if (key === currentKey) {
error.value = e
}
} finally {
if (key === currentKey) {
loading.value = false
}
}
}
watch(
() => [pagination.currentPage, pagination.pageSize],
([currentPage, pageSize]) => _loadData(currentPage, pageSize),
{ immediate: true },
)
return {
data,
loading,
error,
pagination: pagination as Pagination,
/** 手动获取数据 可以修改分页 */
loadData(newPagination: Partial<Pick<Pagination, 'currentPage' | 'pageSize'>> = {}) {
const { currentPage = pagination.currentPage, pageSize = pagination.pageSize } = newPagination
if (currentPage === pagination.currentPage && pageSize === pagination.pageSize) {
// 分页未变化 直接获取数据
_loadData(pagination.currentPage, pagination.pageSize)
return
}
// 分页变化 设置pagination 由watch获取数据
pagination.currentPage = currentPage
pagination.pageSize = pageSize
},
}
}
特点:1.使用key避免网络请求后发先至从 2.利用v-bind简化数据和值的绑定