官方的案例给人误导
<van-pull-refresh v-model="loading" @refresh="onRefresh">
<p>刷新次数: {{ count }}</p>
</van-pull-refresh>
这种结构,不管里面列表会不会滚动,只要下拉一定会触发下拉刷新
文档尾部给的说明
PullRefresh 的触发条件是?
PullRefresh 的触发条件是「父级滚动元素的滚动条在顶部位置」。
- 如果最近一个可滚动的父级元素是
window,则要求window.pageYOffset === 0。 - 如果最近一个可滚动的父级元素是
Element,则要求Element.scrollTop === 0。
基于此的改造方案(渲染的列表较短时推荐)
- van-pull-refresh高度不控制,由内部列表撑开。(可以设置最小高度为列表容器高度)
- van-pull-refresh外部负责控制滚动
<div class="list-container" >
<van-pull-refresh
v-model="loading"
style="min-height: 100%"
@refresh="getAccountList"
>
<div
class="account-item"
v-for="account in accountList"
:key="account.id"
>
<el-avatar
:size="25"
:src="account.imgUrl"
>
<img src="@/assets/avatar.png" />
</el-avatar>
<div class="account-name">{{ account.name }}</div>
</div>
</van-pull-refresh>
</div>
<style>
.list-container {
height: 100%;
overflow-y: auto;
.account-item {
display: flex;
align-items: center;
column-gap: 10px;
+ .account-item {
margin-top: 15px;
}
.account-name {
word-break: break-all;
}
}
}
</style>
常见的复杂的改造方案(若列表很长要用虚拟列表时)
列表很长渲染阻塞,van-pull-refresh里用了虚拟列表,高度是限死的,此时不能利用van-pull-refresh滚动到父容器顶部的特性来触发加载了
这种情况不需要考虑上拉加载,因为如果要用上拉加载,说明一次拉取的数据不多,单次渲染负担不大,也就没必要用虚拟列表。不用虚拟列表,用上面那个常规方案就行
- 给van-pull-refresh增加disabled属性
- van-pull-refresh里面包裹的滚动列表增加scroll监听,滚动到顶部之前,disabled一直为true
<template>
<div>
<van-pull-refresh
v-model="loading"
:disabled="!canPullRefresh"
:head-height="100"
@refresh="getAccountList"
>
<template v-if="accountList.length > 0">
<!-- 虚拟滚动 -->
<RecycleScroller
class="chat-scroller"
:items="accountList"
:item-size="40"
key-field="id"
v-slot="{ item }"
@scroll="scrollDebounce"
>
<div class="account-item">
<el-avatar :size="25" :src="item.imgUrl">
<img src="@/assets/avatar.png" />
</el-avatar>
<div class="account-name">{{ item.name }}</div>
</div>
</RecycleScroller>
</template>
<div class="blank-placehold" v-else>暂无数据,可通过下拉页面进行刷新</div>
</van-pull-refresh>
</div>
</template>
<script setup>
import { ref } from "vue";
import Mock from "mockjs";
import { throttle } from "lodash-es";
const accountList = ref([]);
const loading = ref(false);
// 模拟获取账号列表
function getAccountList() {
loading.value = true;
setTimeout(() => {
loading.value = false;
// 定义生成数据的模板
const dataTemplate = {
"id|+1": 1, // 自增的id属性
name: "@cname", // 使用 @cname 来生成中文名
imgUrl: Mock.Random.image(),
};
// 生成包含 10 个对象的数组
const dataList = Mock.mock({
"list|100": [dataTemplate],
});
accountList.value = dataList.list;
}, 1000);
}
getAccountList();
// 控制是否允许触发下拉刷新(只有滚到页面顶部时下拉,才可触发刷新)
const canPullRefresh = ref(true);
// 防抖在动作终止时才会更新,若滚到顶部后迅速下拉一段又上拉又下拉,会导致触发下拉刷新。故此处用节流
const scrollDebounce = throttle(scrollList, 100);
function scrollList(e) {
const scrollTop = e.target.scrollTop;
// 只有在顶部时才允许触发刷新
canPullRefresh.value = scrollTop <= 0;
}
</script>
<style lang="scss" scoped>
.chat-scroller {
height: 50vh;
.account-item {
display: flex;
align-items: center;
height: 40px;
column-gap: 10px;
}
}
</style>