usePagingRequest & v-infinite-scroll 中后台列表滚动加载配套使用
基于element-plus指令 v-infinite-scroll + 自定义hook函数
usePagingRequest实现
1、指令安装
import { ElInfiniteScroll } from 'element-plus'
app.use(ElInfiniteScroll)
2、usePagingRequest hook函数设计
2.1、返回值设计
/**
* @param loading 请求中
* @param successStatus 请求成功
* @param disabled 对应v-infinite-scroll指令属性infinite-scroll-disabled绑定值
* @param noMore 分页数据全部加载完成
* @param showRetryButton 是否显示数据加载失败重试按钮
* @param query 请求参数
* @param data 加载后的数据列表
* @param load 数据加载方法
* @param setLoading 主动设置请求中状态
* @param setSuccessStatus 主动设置数据加载成功状态
* @param setQuery 主动设置请求参数(增量设置非全部覆盖),用户搜索等查询条件
*/
export interface IUsePagingRequestReturnType<DataItem, RequestParams> {
loading: Ref<boolean | undefined>
successStatus: Ref<boolean | undefined>
disabled: Ref<boolean>
noMore: Ref<boolean>
showRetryButton: Ref<boolean>
query: Ref<UnwrapRef<RequestParams>>
data: Ref<DataItem[]>
load: () => Promise<IPagingResponseData<DataItem>> | undefined
setLoading: (val: boolean) => boolean
setSuccessStatus: (val: boolean) => boolean
setQuery: (params: RequestParams, resetPageNo?: boolean) => void
}
2.2、使用案例
<div
v-infinite-scroll="load"
:infinite-scroll-disabled="disabled"
:infinite-scroll-immediate="true"
>
<ElRadioGroup v-model="checkedProductNo">
<template v-for="item in data" :key="item.productNo">
<ItemProduct
:productName="item.productName"
:productNo="item.productNo"
:desc="item.desc"
:categoryName="item.categoryName"
/>
</template>
</ElRadioGroup>
<div :class="`open-product__loading ${noMore ? 'hidden' : ''}`" v-if="loading">
<span>拼命加载中...</span>
</div>
<div class="open-product__retryload" v-if="showRetryButton" @click="load">
<span>加载失败,点击</span>
<ElButton type="primary" link>重试</ElButton>
</div>
<div class="open-product--nomore" v-if="noMore">没有更多了</div>
</div>
import type { IProductItem, IProductRequestParams } from '@/api/productManage/types'
import { getProductListApi } from '@/api/productManage'
import { usePagingRequest } from '@/hooks/web/usePagingRequest'
const { data, loading, successStatus, showRetryButton, noMore, disabled, load, setQuery } =
usePagingRequest<IProductItem, IProductRequestParams>({
apiMethod: getProductListApi,
transformData: (data) => {
// 这里可以使用map重组新数据列表
return data
},
params: {
pageNo: 1,
pageSize: 20
}
})
2.3、代码实现
export function usePagingRequest<
DataItem extends Recordable,
RequestParams extends Recordable
>(options: {
apiMethod: (...args: any) => Promise<IPagingResponseData<DataItem>>
params: RequestParams
transformData?: (data: DataItem[]) => DataItem[]
pageNoName?: string
pageSizeName?: string
}): IUsePagingRequestReturnType<DataItem, RequestParams> {
const {
apiMethod,
params,
transformData,
pageNoName = 'pageNo',
pageSizeName = 'pageSize'
} = options
const { loading, setLoading } = useLoading(false)
const { status: successStatus, setStatus: setSuccessStatus } = useStatus<boolean>()
const total = ref<number>(0)
const data = ref<DataItem[]>([])
const failLoadRetryRequestPageNoList = ref<number[]>([])
const noMore = computed(() => total.value > 0 && data.value.length >= total.value)
const showRetryButton = computed(() => !loading.value && !successStatus.value && !noMore.value)
const disabled = computed(
() => loading.value || noMore.value || failLoadRetryRequestPageNoList.value.length >= 5
)
const defaultParams = {
...cloneDeep(params),
[pageNoName]: params[pageNoName] || 1,
[pageSizeName]: params[pageSizeName] || 20
}
const query = ref<RequestParams>(defaultParams)
const pageNo = computed(() => query.value[pageNoName])
const setQuery = (params: RequestParams, resetPageNo = true) => {
const newValue = {
...query.value,
...cloneDeep(params)
}
if (resetPageNo) newValue[pageNoName] = params[pageNoName] || 1
query.value = {
...pickBy(newValue, isValidValue)
}
}
const reqParams = computed(() => pickBy(query.value, isValidValue))
const load = () => {
if (loading.value) return
setLoading(true)
data.value = pageNo.value === 1 ? [] : data.value
return apiMethod(reqParams.value)
.then((res) => {
setSuccessStatus(true)
failLoadRetryRequestPageNoList.value = []
total.value = res.total
const records = res?.records || []
const list = (transformData && transformData(records)) || records
data.value = [...data.value, ...list] as UnwrapRef<DataItem[]>
query.value[pageNoName] += 1
return res
})
.catch((err) => {
setSuccessStatus(false)
failLoadRetryRequestPageNoList.value.push(pageNo.value)
return Promise.reject(err)
})
.finally(() => (loading.value = false))
}
return {
loading,
setLoading,
successStatus,
setSuccessStatus,
disabled,
noMore,
showRetryButton,
query,
setQuery,
data,
load
}
}