介绍
在移动端开发中,下拉刷新、上拉加载是列表类页面的核心交互需求。这里使用vant UI框架van-pull-refresh + van-list组件来实现这功能。
官网地址:https://vant.pro/vant/#/zh-CN/
核心原理
- 下拉刷新(van-pull-refresh):监听用户下拉手势,触发刷新逻辑,重置列表数据为第一页,完成后恢复初始状态。
- 上拉加载(van-list): 监听滚动容器触底事件,触发加载逻辑,加载下一页数据,直到无更多数据。
- 状态管理:通过loading(加载中)、finished(加载完成)、refreshing(刷新中)三个状态控制组件交互,避免重复请求。
上拉加载下拉刷新组件
页面结构
javascript
<template>
<van-pull-refresh
v-model="refreshing"
@refresh="onRefresh"
>
<van-list
v-model:loading="loading"
:finished="finished"
:finished-text="list.length === 0 ? '' : '没有更多了'"
@load="onLoad"
:immediate-check="false"
>
<slot :list="list"></slot>
</van-list>
</van-pull-refresh>
</template>
<script lang="ts" setup>
const props = defineProps({
api: {
type: Function,
required: true
},
// 每页条数
pageSize: {
type: Number,
default: 10
}
})
const emit = defineEmits(['update:list', 'refresh'])
// 状态
const list = ref<any>([])
const pageNo = ref(1)
const loading = ref(false)
const refreshing = ref(false)
const finished = ref(false)
// 重置 & 刷新
const onRefresh = async () => {
console.log('refresh')
loading.value = true
pageNo.value = 1
finished.value = false
try {
await fetchData()
} finally {
console.log('结束+++++');
setTimeout(() => {
refreshing.value = false
loading.value = false
}, 300)
}
emit('refresh')
}
// 上拉加载
const onLoad = async () => {
console.log('load')
if (refreshing.value) return
pageNo.value++
await fetchData()
}
// 请求数据
const fetchData = async () => {
try {
const res = await props.api({
pageNo: pageNo.value,
pageSize: props.pageSize
})
if (pageNo.value === 1) {
list.value = res.list || []
} else {
list.value = [...list.value, ...(res.list || [])]
}
// 判断是否加载完
finished.value = list.value.length >= (res.total || 0)
} catch(error) {
if (pageNo.value === 1) {
refreshing.value = false
}
} finally {
loading.value = false
emit('update:list', list.value);
}
}
// 外部强制刷新用
const reload = async () => {
pageNo.value = 1
finished.value = false
list.value = []
await fetchData()
}
defineExpose({ reload, list })
// 初始化
fetchData()
</script>
<style lang="scss" scoped></style>
配置型
| 配置项 | 作用 | 推荐值 |
|---|---|---|
| immediate-check | 是否初始化时立即检测触底 | false(避免页面加载时误触底) |
| offset | 触底检测偏移量(距离底部多少像素触发加载) | 100(增大偏移量减少误触) |
| disabled(pull-refresh) | 刷新时禁用加载 | 绑定 loading(避免刷新和加载同时触发) |
组件使用
javascript
<RefreshList ref="refreshListRef" :api="getData">
<template #default="{ list }">
// 列表数据
</template>
</RefreshList>
<script lang="ts" setup>
const getData = async ({ pageNo, pageSize }) => {
try {
const result = await getList({ ...formData, pageNo, pageSize })
return {
list: result.list,
total: result.total
}
} catch (error) {
console.log(error)
}
}
</script>
