项目背景

在我的开源项目 homie 匹配(http://hm.hejiajun.icu/)的首页中就是利用的 vue-infinite-loading 组件实现的滑动加载,整体的引入和使用还是比较简单的,下面由我带大家快速上手吧。

快速上手

官网:Configure Load Messages | Vue-infinite-loading

1.安装依赖:

1
npm install v3-infinite-loading

2.在 main.ts 或者要用到的文件中全局引入,我是在用到的

1
import InfiniteLoading from "v3-infinite-loading";

3.引入组件:

1
2
3
<div style="display: flex; justify-content: center;">
<infinite-loading :identifier="infiniteId" @infinite="loadMore" v-if="!isMatchMode"/>
</div>

4.定义加载更多函数,目的是不断增加页数,通过 hasMoreData 来判断是否有更多数据,有就增加页数,当组件触发到页面底部是就会调用这个函数,然后你就可以添加分页的参数,以便查询下一页数据。

1
2
3
4
5
6
const loadMore = () => {
if (hasMoreData.value) {
pageNum++;
loadData();
}
};

5.有人会问 hasMoreData 的作用是什么,它的作用主要是判断是否用更多的数据(布尔值),当滑动页面时前端会不断请求下一页的数据,如果后端返回前端的数据大于 0 就代表还有更多的数据那么值就为 true,否则就没有那么就为 false。因此可以通过这个参数来控制页数的是否需要增加,如果没有的话就会一直请求后端,会给服务器增加很多压力。

这个边我贴一下前端请求后端数据和后端返回数据的一个大致代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
userListData = await myAxios.get('/user/recommend', {
params: { pageSize: 3, pageNum },
}).then(response => {
console.log('/user/recommend succeed', response);
return response?.data;
}).catch(error => {
console.log('/user/recommend error', error);
});

if (userListData) {
userListData.forEach((user: UserType) => {
if (user.tags) {
user.tags = JSON.parse(user.tags);
}
});

if (pageNum === 1) {
userList.value = userListData;
} else {
userList.value = [...userList.value, ...userListData];
}

hasMoreData.value = userListData.length > 0;
}

loading.value = false;

以下是整体代码,想深入研究或者没理解的可以看看整体的逻辑,如果引入时出现问题可以私信我。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
<template>
<van-search v-model="searchText" placeholder="搜索附近用户" @search="onSearch(searchText)"/>
<van-cell center title="心动模式">
<template #right-icon>
<van-switch v-model="isMatchMode" size="24" @change="onMatchModeChange"/>
</template>
</van-cell>

<user-card-list :user-list="userList" :loading="loading"/>
<van-back-top right="15vw" bottom="10vh" />
<div style="display: flex; justify-content: center;">
<infinite-loading :identifier="infiniteId" @infinite="loadMore" v-if="!isMatchMode"/>
</div>
<van-empty v-if="!userList || userList.length < 1" description="数据为空"/>
</template>

<script setup lang="ts">
import {ref, watchEffect} from "vue";
import {useRoute} from "vue-router";

import myAxios from "../plugins/myAxios.ts";
import UserCardList from "../components/UserCardList.vue";
import {UserType} from "../models/user"
import {showToast} from "vant";
import InfiniteLoading from "v3-infinite-loading";

const route = useRoute();
const {tags} = route.query;
const searchText = ref('');
const userList = ref<UserType[]>([]);
const isMatchMode = ref<boolean>(false);
const loading = ref(true);
const infiniteId = 'infinite-loading-id';

let pageNum = 1;
let hasMoreData = ref(true);

/**
* 加载数据
*/
const loadData = async () => {
let userListData;
loading.value = true;

if (isMatchMode.value) {
const num = 10;
userListData = await myAxios.get('/user/match', {
params: { num },
}).then(response => {
console.log('/user/match succeed', response);
return response?.data;
}).catch(error => {
console.log('/user/match error', error);
});

if (userListData) {
userListData.forEach((user: UserType) => {
if (user.tags) {
user.tags = JSON.parse(user.tags);
}
});
}

userList.value = userListData || [];
loading.value = false;
hasMoreData.value = false;

} else {
userListData = await myAxios.get('/user/recommend', {
params: { pageSize: 3, pageNum },
}).then(response => {
console.log('/user/recommend succeed', response);
return response?.data;
}).catch(error => {
console.log('/user/recommend error', error);
});

if (userListData) {
userListData.forEach((user: UserType) => {
if (user.tags) {
user.tags = JSON.parse(user.tags);
}
});

if (pageNum === 1) {
userList.value = userListData;
} else {
userList.value = [...userList.value, ...userListData];
}

hasMoreData.value = userListData.length > 0;
}

loading.value = false;
}
};

const onMatchModeChange = () => {
userList.value = [];
pageNum = 1;
hasMoreData.value = true;
loadData();
};

const loadMore = () => {
if (hasMoreData.value) {
pageNum++;
loadData();
}
};

const onSearch = async (searchText: string) => {
let userListData;
loading.value = true;

const res = await myAxios.get('/user/searchNearby', {
params: { radius: searchText }
});

if (res?.code === 0) {
userListData = res?.data;

if (userListData) {
userListData.forEach((user: UserType) => {
if (user.tags) {
user.tags = JSON.parse(user.tags);
}
});

userList.value = userListData;
}

loading.value = false;

} else {
showToast('搜索失败' + (res.description ? `,${res.description}` : ''));
}

loading.value = false;
};

watchEffect(() => {
loadData();
});

</script>

<style scoped>
</style>

效果

当我向下滑动时,是不是就会发送请求下一页数据的请求啊,当我拉到最下面时也就停止请求了,是吧?

我的开源项目

如果你对我的开源项目(http://hm.hejiajun.icu/)感兴趣的话,可以看看它的介绍 我终于有我的开源项目了!!!-CSDN博客 哦,后续我还会介绍这个项目的更多亮点和实现原理,如果有帮到你的话不放帮我点个关注,谢谢!