uni-app下拉加载更多

任何一个库在网上都褒贬不一,uni-app同样如此,对于不是太熟悉前端开发的人员来说使用这样一个库能让我们的开发效率提高不少,如果你想一套代码,发布到多个平台,那么uni-app也是一个很不错的选择。

如果你想了解更多关于uni-app的知识请自行官网查看,我这里今天只记录下一个关于上拉刷新和下拉加载的小功能。

其实关于加载更多这个插件,官方已经为我们提供了,放在扩展组件中,当然这个组件只是为我们实现了上拉加载的按钮显示样式,具体的获取数据逻辑还是需要我们自己去编写。

效果预览

转的图片有点大,没工夫找工具了。

分析数据结构

我们获取数据的逻辑是要根据目标接口返给我们的的数据结构来编写的,我们先来看下目标返回的大概结构。

我们放收尾和中间任意一页的数据结构给大家看。

第一页

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
{
"next": "http://127.0.0.1:8000/api/v1/lecture/?page=bz0z&size=3",
"previous": null,
"results": [
{
"id": 80,
"name": "完成能够阅读.",
"start_time": "2020-09-27T16:35:46",
"address": "江西省海口县上街贵阳街v座 930357",
"thumbnail": "https://www.lorempixel.com/750/450",
},
{
"id": 79,
"name": "规定更多系列密码其实.",
"start_time": "2020-09-27T02:33:48",
"address": "甘肃省秀英县合川周街a座 342016",
"thumbnail": "https://placekitten.com/750/450",
},
{
"id": 78,
"name": "能够应该首页免费.",
"start_time": "2020-10-22T21:02:58",
"address": "山东省洋县南湖吴街g座 247551",
"thumbnail": "https://dummyimage.com/750x450",
}
]
}

第二页

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
{
"next": "http://127.0.0.1:8000/api/v1/lecture/?page=bz02&size=3",
"previous": "http://127.0.0.1:8000/api/v1/lecture/?page=cj0xJnA9MTAw&size=3",
"results": [
{
"id": 77,
"name": "价格觉得项目有限作品帮助.",
"start_time": "2020-09-19T05:14:11",
"address": "河北省莹县平山侯路H座 848604",
"thumbnail": "https://placekitten.com/750/450",
},
{
"id": 76,
"name": "这是他的因此因此.",
"start_time": "2020-10-13T02:20:59",
"address": "贵州省西安市淄川马路b座 421301",
"thumbnail": "https://www.lorempixel.com/750/450",
},
{
"id": 74,
"name": "其实一点发表科技事情.",
"start_time": "2020-10-25T20:03:47",
"address": "四川省凤英市门头沟张街B座 755654",
"thumbnail": "https://dummyimage.com/750x450",
}
]
}

最后一页

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
{
"next": null,
"previous": "http://127.0.0.1:8000/api/v1/lecture/?page=bz0zJnI9MQ%3D%3D&size=3",
"results": [
{
"id": 4,
"name": "精华业务进入.",
"start_time": "2020-11-03T01:30:23",
"address": "云南省春梅市沙市银川路Y座 310692",
"thumbnail": "https://www.lorempixel.com/750/450",
},
{
"id": 3,
"name": "还有那么注意精华.",
"start_time": "2020-09-26T22:04:27",
"address": "新疆维吾尔自治区兰州县高坪王街v座 401585",
"thumbnail": "https://dummyimage.com/750x450",
},
{
"id": 2,
"name": "技术服务如此本站软件不要.",
"start_time": "2020-09-28T12:23:53",
"address": "北京市梅县城北成都路B座 221544",
"thumbnail": "https://placekitten.com/750/450",
}
]
}

我这里要说明下,为了代码不那么长我们这里都是每页3条来显示的,实际项目中肯定每页不止3条。另外分析接口返回数据可以得知,页码是加密的,我们不知道下一页的页码是什么(接口服务用的django,其第三方包DjangoRestFramework中分页自带有这个功能),其他可以看出来的就是最后一页的next页为null,利用这点我觉得我们可以就依据这个下一页字段,没有下一页字段代表数据读取完了。

获取数据逻辑

初始化

默认进去该页面肯定会默认显示几条数据。我们可以在onload里直接编写一下代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
uni.request({
url: "你的接口地址",
success: (res) => {
if (res.statusCode == 200) {
this.list = res.data.results
} else {
console.log("出错了,联系管理员吧")
}
},
fail: (err) => {
console.log("出错了,联系管理员吧")
}
})

生命周期

在uni-app页面生命周期中有一个onReachBottom,它就是负责页面上拉触底事件的处理函数。我们将刚才写的request请求写到一个方法中,方法名为get_list(),生命周期onReachBottom中如下书写:

1
2
3
onReachBottom() {
this.get_list()
},

优化获取数据逻辑

我们当然可以在上拉加载更多时重写写一个请求方法,但是为了代码复用,我们最好是在原来请求代码的数据上进行修改,毕竟待会儿下拉刷新页面的时候也要重新发起请求。

简单分析下流程:下拉页面请求新数据-》将新数据追加到老数据后面-》直到所有数据全部请求完。

在分析数据结构中我们可以得出没有下一页了即代码数据全部请求完了,我们来定义一个参数来存放下一页链接。

初步尝试
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
<script>
import uniLoadMore from '@/components/uni-load-more/uni-load-more.vue'
export default {
data() {
components: {
uniLoadMore
}
return {
// 存放列表数据
list: [],
// 下拉状态
status: 'more',
contentText: {
contentdown: '上拉加载更多',
contentrefresh: '加载中',
contentnomore: '没有更多'
},
// 下一页链接
next_url: ''
}
},
onReachBottom() {
this.get_lecture()
},
onLoad() {
// 初始获取数据
this.get_list()
},
methods: {
get_list: function() {
// 初始默认获取数据链接
var url = `目标接口地址`
// 如果下一页链接存在则代表上拉加载时获取数据的链接url
if (this.next_url) {
url = this.next_url
}

// 请求数据
uni.request({
url: url,
success: (res) => {
if (res.statusCode == 200) {
// 当前以后数据连接新获取的数据
this.list = this.list.concat(res.data.results)
// 页面返回的下一页链接赋值给next_url
this.next_url = res.data.next
} else {
console.log("出错了,联系管理员吧")
}
},
fail: (err) => {
console.log("出错了,联系管理员吧")
}
})
},
}
}
</script>

如果你看了代码不知道有没有发现其中的bug,我是没有发现,我是在预览页面时才发现了有问题的。

这个bug就是当你获取完所有的数据之后,又开始从第一篇文章开始获取了,因为所有页面获取完之后next_url的值为null了,所以又重新获取初始数据,所以我们要区分是第一次进来的还是数据加载完了。

我这里用了一个最Low的办法,初始的时候直接将next_url设为false了;正常该值为string的url链接;访问完所有数据next_url为null。区分下这三种状态就可以了。

代码优化
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
<script>
import uniLoadMore from '@/components/uni-load-more/uni-load-more.vue'
export default {
data() {
components: {
uniLoadMore
}
return {
list: [],
// 下拉状态
status: 'more',
contentText: {
contentdown: '上拉加载更多',
contentrefresh: '加载中',
contentnomore: '没有更多'
},
// 下一页链接
next_url: false
}
},
onReachBottom() {
this.satus = "more"
this.get_list()
},
onLoad() {
// 初始获取数据
this.get_list()
},
methods: {
// 获取热点资讯
get_list: function() {
// 初始默认获取数据链接
var url = `初始目标接口地址`
// 判断如果下一页链接为false代表第一次访问数据;如果为null代表已加载完所有数据了;否则可以加载更多数据。
if (this.next_url == false) {
// 首次访问,默认访问首页链接
url = `初始目标接口地址`
} else if (this.next_url == null) {
// 代表加载完所有数据,即没有更多数据了
url = null
// 显示没有更多文本
this.status = "noMore"
// 直接返回,不往下执行
return false
} else {
// 代表已有数据,且还可以加载更多数据
url = this.next_url
}


uni.request({
url: url,
success: (res) => {
if (res.statusCode == 200) {
// 当前以后数据连接新获取的数据
this.list = this.list.concat(res.data.results)
// 页面返回的下一页链接赋值给next_url
this.next_url = res.data.next
} else {
console.log("出错了,联系管理员吧")
}
},
fail: (err) => {
console.log("出错了,联系管理员吧")
}
})
},
}
}
</script>

下拉刷新

相对于上拉加载更多,那么下拉刷新就简单的多了,无非是清空原有代码,初始化原始next_url为false,后面就跟第一次访问一样了,但是这其中包含两个要注意的点:

  1. 要使用下拉刷新需要在page页对应该页面的style属性中开启enablePullDownRefresh

    即:

    1
    2
    3
    4
    5
    6
    {
    "path" : "页面链接",
    "style" : {
    "enablePullDownRefresh" : true
    }
    }
  2. 下拉刷新的时候有个旋转的动画,下拉之后它一直在旋转,我们需要在请求完成后手动结束这个动画

    结束的方法为:uni.stopPullDownRefresh()

下拉刷新代码很简单,同样存在在页面生命周期中

1
2
3
4
5
6
7
8
9
10
onPullDownRefresh() {
// 下拉刷新
// 清空数据
this.list = []
// 下一页链接置为false,代表第一次获取数据
this.next_url = false
// 开始获取数据
this.get_list()

},

全部代码

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
<template>
<view>
<view class="bg-white padding-lr-xs">
<navigator url="detail" class="flex" v-for="(item, index) in list" :key="item.id">
<view class="flex-sub margin-xs radius">
<image :src="item.thumbnail" class="lecture_img" mode="widthFix"></image>
</view>
<view class="flex-twice margin-xs lecture_text">
<view class="text-cut padding-bottom-xs">
{{item.id}}{{item.name}}
</view>
<view class="lecture_location">
<text class="cuIcon-location padding-right-sm"></text> {{item.address}}
</view>
<view class="lecture_date">
<text class="cuIcon-time padding-right-sm"></text>
{{item.start_time}}
</view>

</view>
</navigator>
<uni-load-more :status="status" :icon-size="16" :content-text="contentText" />
</view>
</view>
</template>

<script>
import uniLoadMore from '@/components/uni-load-more/uni-load-more.vue'
export default {
data() {
components: {
uniLoadMore
}
return {
list: [],
// 下拉状态
status: 'more',
contentText: {
contentdown: '上拉加载更多',
contentrefresh: '加载中',
contentnomore: '没有更多'
},
// 下一页链接
next_url: false
}
},
onPullDownRefresh() {
// 下拉刷新
// 清空数据
this.list = []
// 下一页链接置为false,代表第一次获取数据
this.next_url = false
// 开始获取数据
this.get_list()

},
onReachBottom() {
// 获取更多数据,
this.status = 'more';
this.get_list()
},
onLoad() {
// 初始获取数据
this.get_list()
},
methods: {
// 获取热点资讯
get_list: function() {
// 请求提交的参数
var data = {}
// 初始默认获取数据链接
var url = `默认接口地址`
// 判断如果下一页链接为false代表第一次访问数据;如果为null代表已加载完所有数据了;否则可以加载更多数据。
if (this.next_url == false) {
// 首次访问,默认访问首页链接
url = `默认接口地址`
} else if (this.next_url == null) {
// 代表加载完所有数据,即没有更多数据了
url = null
// 显示没有更多文本
this.status = "noMore"
// 直接返回,不往下执行
return false
} else {
// 代表已有数据,且还可以加载更多数据
url = this.next_url
}


uni.request({
url: url,
success: (res) => {
if (res.statusCode == 200) {
// 当前以后数据连接新获取的数据
this.list = this.list.concat(res.data.results)
// 页面返回的下一页链接赋值给next_url
this.next_url = res.data.next
// 停止当前页面下拉刷新动画
uni.stopPullDownRefresh()
} else {
uni.showModal({
showCancel: false,
content: "出错了,联系管理员吧"
})
}
},
fail: (err) => {
console.log(err)
uni.showModal({
showCancel: false,
content: "出错了,联系管理员吧"
})
}
})
},
}
}
</script>

<style>
.lecture_text {
overflow: hidden;
}

.lecture_img {
width: 100%;
}

.lecture_title {
white-space: nowrap;
text-overflow: ellipsis;
padding-bottom: 10px;
}

.lecture_location,
.lecture_date {
line-height: 20px;
font-size: 12px;
color: #AAAAAA;
}
</style>