父组件使用
<template>
<PullRefreshList ref="PullRefreshListRef" :requestApi="requestApi" :requestParams="requestParams">
<template v-slot="{ data }">
// 列表内容
// <ListContent :data="data"></ListContent>
</template>
</PullRefreshList>
</template>
<script setup>
import { ref, computed, reactive } from "vue"
import PullRefreshList from '@/components/PullRefreshList.vue'
import ListContent from './components/ListContent.vue'
import axios from "axios"
// 列表请求
const PullRefreshListRef = ref(null)
const requestApi = (params) => {
const { pageParams, requestParams,cancelToken } = params
return axios({ url: "请求url", method: "GET", params: { ...pageParams, ...requestParams }, cancelToken })
}
// 请求参数
const requestParams = computed(() => {
return {}
})
</script>
子组件 PullRefreshList.vue
<template>
<van-pull-refresh v-model="refreshing" @refresh="onRefresh">
<van-list v-model:loading="loading" v-model:error="error" :finished="finished" @load="onLoad"
:offset="props.offsetList" :loading-text="props.loadingTextList" :finished-text="props.finishedTextList"
:error-text="props.errorTextList" :immediate-check="props.immediateCheckList" :disabled="props.disabledList"
:direction="props.directionList">
<template v-for="item in listData" v-if="listData.length > 0">
<slot :data="item"></slot>
</template>
<van-empty description="暂无数据" v-else />
</van-list>
</van-pull-refresh>
</template>
<script setup>
import { ref, reactive, watch } from 'vue';
import axios from "axios"
import { debounce } from "@/utils";
const props = defineProps({
requestApi: Function, // 请求数据api
requestError: Function, // 请求错误处理
dataCallBack: Function, // 返回数据的回调函数,可以对数据进行处理
requestParams: {
type: Object,
default: {}
}, // 请求参数
offsetList: {
type: Number || String,
default: 0
}, // 滚动条与底部距离小于 offset 时触发 load 事件 number | string 300
loadingTextList: {
type: String,
default: '加载中...'
}, //加载过程中的提示文案 string 加载中...
finishedTextList: {
type: String,
default: '加载完成,暂无更多'
}, //加载完成后的提示文案 string -
errorTextList: {
type: String,
default: '获取失败,点击重新获取'
}, //加载失败后的提示文案 string -
immediateCheckList: {
type: Boolean,
default: true
}, //是否在初始化时立即执行滚动位置检查 boolean true
disabledList: {
type: Boolean,
default: false
}, //是否禁用滚动加载 boolean false
directionList: {
type: String,
default: 'down'
}, //滚动触发加载的方向,可选值为 up
})
// 下拉刷新是否处于加载中状态
const refreshing = ref(false)
// 上拉加载是否处于加载中状态
const loading = ref(false)
// 上拉加载失败
const error = ref(false)
// 是否已加载完成,加载完成后不再触发 load 事件
const finished = ref(false)
const pageParams = reactive({
current: 1, // 当前页
size: 10, // 每页数据条数
total: 0, // 总页数
})
// 列表数据
const listData = ref([])
// 下拉刷新
const onRefresh = () => {
handleReset();
requestData(1)
}
// 上拉加载
const onLoad = () => {
if (error.value) return
requestData(2)
}
// 关闭加载状态
const loadStatus = (boolean) => {
refreshing.value = boolean
loading.value = boolean
}
// 初始化
const handleReset = () => {
pageParams.current = 1
finished.value = false
error.value = false
}
// 监听请求参数是否发生变化
watch(() => props.requestParams, () => {
onRefresh()
})
// 当前是否在请求中
const isRequest = ref(false)
let cancelFn = () => { }
/*
*@functionName: requestData
*@params1: type 1 下拉刷新 2 上拉加载
*@description: 加载列表数据
*/
const requestData = (type, params = {}) => {
if (!props.requestApi) {
throw '请传入requestApi'
}
// 取消上次请求
if (isRequest.value) {
cancelFn();
}
loadStatus(true)
debounceSendRequest(type, params)
}
const sendRequest = async (type, params) => {
try {
isRequest.value = true
const { data } = await props.requestApi({
pageParams: pageParams,
requestParams: { ...props.requestParams, ...params },
cancelToken: new axios.CancelToken(callBack => {
cancelFn = callBack
})
})
isRequest.value = false
let requestData = data.data
loadStatus(false)
props.dataCallBack && (requestData = props.dataCallBack(requestData))
if (requestData.records.length < pageParams.size) {
finished.value = true
}
if (type === 1) {
listData.value = requestData.records
} else {
listData.value = listData.value.concat(requestData.records)
}
pageParams.current++
pageParams.size = requestData.size || pageParams.size
pageParams.total = requestData.total || pageParams.total
} catch (err) {
isRequest.value = false
if (err.code === "ERR_CANCELED") {
return
}
if (type === 2) {
error.value = true
}
loadStatus(false)
props.requestError && props.requestError(err);
}
}
let debounceSendRequest = debounce(sendRequest, 300)
const reLoad = (params) => {
handleReset();
requestData(1, params)
}
defineExpose({
onRefresh,
reLoad
})
</script>