在移动应用开发中,无限滚动加载是一个常见的功能,用户可以通过滑动屏幕来加载更多的内容,从而提高应用的用户体验。本文将介绍如何使用Uniapp实现无限滚动加载的功能。
概述
我们需要实现的无限滚动加载功能的具体效果如下:
-
当用户滑动到底部时,自动加载更多的数据。
-
在加载数据时,显示一个加载动画,防止用户误以为应用已经崩溃。
-
当所有数据都已经加载完毕时,提示用户“没有更多数据了”。
方案
我们可以通过以下步骤来实现无限滚动加载功能:
-
在
cs.vue
组件中,使用uni.createIntersectionObserver()
方法创建一个交叉观察器,用于观察加载动画是否进入了用户的视图区域。 -
在交叉观察器的回调函数中,判断加载动画是否进入了用户的视图区域,并根据需要加载更多的数据。
-
在加载数据时,使用事件来控制加载动画的出现与隐藏。
-
当所有数据都已经加载完毕时,使用事件来控制“没有更多数据了”的提示是否显示。
-
在
index.vue
组件中,引入cs.vue
组件,并通过事件来控制加载动画和“没有更多数据了”的提示是否显示。
实现
在cs.vue
组件中,我们需要使用事件来控制加载动画的出现与隐藏。具体来说,当交叉观察器的回调函数中判断需要加载数据时,我们需要通过$emit
方法触发一个名为aaa
的事件,并传递参数0,表示加载动画需要出现。当数据加载完毕后,我们再次触发aaa
事件,并传递参数1,表示加载动画需要消失。代码如下:
if (res.intersectionRatio > 0) {
this.$emit("aaa", 0); // 加载动画出现
setTimeout(() => {
this.a += 10;
this.$emit("aaa", 1); // 加载动画消失
}, 3000)
}
在cs.vue
组件中,我们还需要使用事件来控制“没有更多数据了”的提示是否显示。具体来说,当所有数据都已经加载完毕时,我们需要通过$emit
方法触发一个名为aaa
的事件,并传递参数2,表示“没有更多数据了”的提示需要显示。代码如下:
if (this.a > 50) return this.$emit("aaa", 2);
在index.vue
组件中,我们需要引入cs.vue
组件,并通过事件来控制加载动画和“没有更多数据了”的提示是否显示。具体来说,我们需要监听aaa
事件,并根据传递的参数来控制加载动画和“没有更多数据了”的提示是否显示。代码如下:
<template>
<view class="container">
<text>{{appear === 0 ? '小球出现' : '小球消失'}}</text>{{appear}}
<view class="page-section">
<scroll-view class="scroll-view" scroll-y>
<cs :appear="appear" @aaa="(val) => appear=val"></cs>
</scroll-view>
</view>
</view>
</template>
<script>
import cs from './cs.vue';
let observer = null;
export default {
components: {
cs
},
data() {
return {
appear: 1
}
},
}
</script>
最后,为了避免内存泄漏,我们需要在cs.vue
组件销毁时将交叉观察器断开连接。具体来说,我们需要在onUnload
生命周期函数中使用disconnect()
方法将交叉观察器断开连接。代码如下:
onUnload() {
if (observer) {
observer.disconnect()
}
}
至此,我们就完成了无限滚动加载的实现。完整代码如下:
cs.vue
组件代码:
<template>
<view>
<view class="item" v-for="item of a" :key="item">
{{item}}锄禾日当午
</view>
<qiuy-loading class="ball" :class="{'is':appear===0}"></qiuy-loading>
<view v-show="appear===2">
没有数据了
</view>
</view>
</template>
<script>
let observer = null;
import QiuyLoading from './QiuyLoading.vue'
export default {
components: {
QiuyLoading
},
props: ["appear"],
data() {
return {
a: 20
}
},
mounted() {
observer = uni.createIntersectionObserver(this);
observer.relativeTo('.scroll-view').observe('.ball', (res) => {
// 当a》50时,停止加载
if (this.a > 50) return this.$emit("aaa", 2);
// 如果当前状态已经在加载中,则不进行。
if (this.appear !== 1) return;
// 出现了
if (res.intersectionRatio > 60) {
// 先让加载动画显示出来
this.$emit("aaa", 0);
setTimeout(() => {
this.a += 10;
// 加载出了数据,关闭加载动画
this.$emit("aaa", 1);
}, 3000)
}
})
},
onUnload() {
if (observer) {
observer.disconnect()
}
}
}
</script>
<style>
.notice {
margin-top: 150rpx;
margin: 150rpx 0 400rpx 0;
}
.is {
height: auto;
overflow: hidden;
}
.item {
line-height: 100rpx;
font-size: 40rpx;
}
</style>
index.vue
组件代码:
<template>
<view class="container">
<text>{{appear === 0 ? '小球出现' : '小球消失'}}</text>{{appear}}
<view class="page-section">
<scroll-view class="scroll-view" scroll-y>
<cs :appear="appear" @aaa="(val) => appear=val"></cs>
</scroll-view>
</view>
</view>
</template>
<script>
import cs from './cs.vue';
let observer = null;
export default {
components: {
cs
},
data() {
return {
appear: 1
}
},
}
</script>
<style>
.scroll-view {
height: 800rpx;
background: #fff;
border: 1px solid #ccc;
box-sizing: border-box;
/* padding-bottom: 30px; */
}
.scroll-area {
height: 1300rpx;
display: flex;
flex-direction: column;
align-items: center;
transition: .5s;
}
</style>
QiuyLoading.vue里的内容
<template>
<view class="loader">
<view class="l">L</view>
<view class="o">o</view>
<view class="a">a</view>
<view class="d">d</view>
<view class="i">i</view>
<view class="n">n</view>
<view class="g">g</view>
<view class="d1">.</view>
<view class="d2">.</view>
</view>
</template>
<script>
</script>
<style>
.loader {
text-align: center;
height: 0;
overflow: hidden;
}
.is {
height: auto;
padding-bottom: 20rpx;
}
</style>
最后,看下效果吧!