uni-app
一、 下拉刷新的方式
由于之前用的是ColorUi
的库,tabbar是通过切换组件的方式来自定义,并没有用原生的tabbar,所以一直苦恼组件中没有像页面的上拉触底函数:onReachBottom()
函数、下拉刷新函数:onPullDownRefresh()
1. 原生下拉刷新
1.pages.json中定义
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| { "pages": [ { "path": "pages/index/index", "style": { "enablePullDownRefresh": true, "app-plus": { "scrollIndicator": "none", "bounce": "none", "pullToRefresh": { "support": true, "style": "circle", "offset": "70px" }
} } } ] }
|
2.在页面上监听下拉动作进行需要的操作
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| <script> export default { onPullDownRefresh() {//监听下拉刷新的函数同onload()同级 uni.startPullDownRefresh({//放下拉后要重新调用的接口 success() { //成功回调 }, fail() { //失败回调 } })
uni.stopPullDownRefresh() //停止下拉刷新 } } </script>
|
Tips:
总结:
- 优点:相对稳定,写法相对简单
- 缺点:样式上固定的,所以不能满足全部人的需求
2. <srcoll-view>
组件
更多srcoll-view
组件详情以及参数参考:scroll-view组件文档
1.页面中使用
1 2 3 4 5 6 7 8
| <template> <view> <scroll-view scroll-y class="page" refresher-enabled="true" :refresher-triggered="triggered" :refresher-threshold="100" refresher-background="lightgreen" @refresherrefresh="onRefresh"> <!--内容--> </scroll-view> </view> </template>
|
2.在页面上监听下拉动作进行需要的操作
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| <script> export default { data() { return { triggered: false//设置当前下拉刷新触发状态 } }, methods: { //自定义下拉刷新被触发 onRefresh: function() { this.$data.triggered = true setTimeout(() => {//延迟模拟请求后自动关闭下拉触发状态 this.$data.triggered = false }, 1000)
console.log("触发onRefresh"); } }} </script>
|
Tips:
- APP-vue和小程序中,请勿在 scroll-view 中使用 map、video 等原生组件。小程序中 scroll-view 中也不要使用 canvas、textarea 原生组件。更新:微信基础库2.4.4起支持了原生组件在 scroll-view、swiper、movable-view 中的使用。app-nvue无此限制。
- scroll-view 不适合放长列表,有性能问题。长列表滚动和下拉刷新,应该使用原生导航栏搭配页面级的滚动和下拉刷新实现。包括在app-nvue页面,长列表应该使用list而不是scroll-view。
- scroll-into-view 的优先级高于 scroll-top。
- scroll-view是区域滚动,不会触发页面滚动,无法触发pages.json配置的下拉刷新、页面触底onReachBottomDistance、titleNView的transparent透明渐变。
- 若要使用下拉刷新,建议使用页面的滚动,而不是 scroll-view 。插件市场有前端模拟的基于scroll-view的下拉刷新,但性能不佳。如必需使用前端下拉刷新,推荐使用基于wxs的下拉刷新,性能会比基于js监听方式更高。
- 如果遇到scroll-top、scroll-left、refresher-triggered属性设置不生效的问题参考:组件属性设置不生效解决办法
- scroll-view的滚动条设置,可通过css的-webkit-scrollbar自定义,包括隐藏滚动条。(app-nvue无此css)
总结:
- 优点:刷新的样式可以自定义相对灵活
- 缺点:
srcoll-view
相对不稳定偶尔会出现下拉不刷新的情况,不适合放长列表,有性能问题
mescroll的uni版本, 是在 uni-app 运行的下拉刷新和上拉加载的组件,提供<mescroll-body>
和<mescroll-uni>
两个组件, 其中<mescroll-body>
支持配置成系统自带的下拉组件, 支持一套代码编译到iOS、Android、H5、小程序等多个平台,本身这个框架就是已经比较完善了的也是很实用,还是比较推荐使用<mescroll-body>
的,更多详情对比参考:mescroll-uni官网文档
4. <refresh>
组件(推荐)
uniapp 提供了 <refresh>
组件,可以用来实现下拉刷新功能。你可以在组件的模板中添加 <refresh>
标签,并在 @refresh
事件中执行刷新操作,如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| <template> <div> <refresh @refresh="onRefresh"> <!-- 组件内容 --> </refresh> </div> </template> <script> export default { methods: { onRefresh() { // 执行刷新操作 } } } </script>
|
5. touchstart
、touchmove
、touchend
等手势事件
如果想要自定义下拉刷新的样式和效果,可以使用 touchstart
、touchmove
、touchend
等手势事件来监听用户的下拉操作,然后实现自定义的下拉刷新效果,效果如下:
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
| <template> <div class="container" @touchstart="onTouchStart" @touchmove="onTouchMove" @touchend="onTouchEnd"> <!-- 组件内容 --> </div> </template>
<script> export default { data() { return { startY: 0, refreshing: false }; }, methods: { onTouchStart(event) { this.startY = event.touches[0].clientY; }, onTouchMove(event) { if (event.touches[0].clientY - this.startY > 50) { // 触发下拉刷新效果 this.refreshing = true; } }, onTouchEnd() { if (this.refreshing) { // 执行刷新操作 this.onRefresh(); this.refreshing = false; } }, onRefresh() { // 执行刷新操作 } } } </script>
|
二、上拉加载更多的方式
1. 原生上拉加载更多
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
| <template> <view> <!-- 页面内容区域 --> <view v-for="(item, index) in dataList" :key="index" class="item"> <!-- 显示内容 --> {{ item }} </view>
<!-- 加载更多提示 --> <view v-if="loadingMore" class="loading-more"> 加载中... </view> </view> </template>
<script> export default { data() { return { dataList: [], // 存放数据的数组 loadingMore: false, // 是否正在加载更多 }; }, onReachBottom() { // 上拉触底事件处理 if (!this.loadingMore) { this.loadingMore = true; // 模拟异步加载更多数据 setTimeout(() => { this.loadMoreData(); }, 1000); } }, methods: { // 模拟加载更多数据 loadMoreData() { // 假设每次加载10条数据 const newData = Array.from({ length: 10 }, (_, index) => `Item ${this.dataList.length + index + 1}`); this.dataList = this.dataList.concat(newData); this.loadingMore = false; // 加载完成后将 loadingMore 设置为 false }, }, }; </script>
<style> /* 样式可根据实际需求进行调整 */ .item { padding: 20rpx; border-bottom: 1px solid #eee; }
.loading-more { text-align: center; padding: 20rpx; color: #999; } </style>
|
2. <srcoll-view>
组件
1.页面中使用
1 2 3 4 5 6 7 8 9 10 11
| <template> <view> <scroll-view scroll-y class="page" style="height:100vh;" @scrolltolower="onLoadMore"> <!--内容--> </scroll-view> <view class="flex justify-center margin-top-xl"> <text v-if="loadingFlag==1" class="text-gray">加载中</text> <text v-if="loadingFlag==2" class="text-gray">没有更多数据</text> </view> </view> </template>
|
2.在页面上监听下拉动作进行需要的操作
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| <script> export default { data() { return { loadingFlag: 0//0:默认状态;1:加载中;2:没有更多数据 } }, methods: { //自定义下拉刷新被触发 onLoadMore: function() { this.$data.loadingFlag = 1//将状态置为加载中 setTimeout(() => {//延迟模拟请求后将状态置位无更多数据 this.$data.loadingFlag = 2 }, 1000)
console.log("触发scrolltolower"); } } } </script>
|
Tips跟优缺点就不再做过多的阐述了,自行参考1.1.2. srcoll-view下拉刷新
同1.1.3.mescroll-uni下拉刷新一样就不过多阐述了
4. 使用滚动事件
在组件中,你可以监听滚动事件,当用户滚动到底部时,触发加载更多的操作。具体步骤如下:
- 在组件的模板中,绑定一个滚动事件监听器,例如:
1 2 3 4 5
| <template> <div class="scroll-container" @scroll="handleScroll"> <!-- 组件内容 --> </div> </template>
|
2.在 handleScroll
方法中,根据滚动距离和容器的高度来判断用户是否滚动到了底部,然后触发加载更多的操作
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| <script> export default { methods: { handleScroll(event) { const container = event.target; const scrollHeight = container.scrollHeight; const scrollTop = container.scrollTop; const clientHeight = container.clientHeight; if (scrollHeight - scrollTop - clientHeight <= 10) { // 触发加载更多的操作 this.loadMoreData(); } }, loadMoreData() { // 执行加载更多的逻辑 } } } </script>
|
5.使用 Intersection Observer
这是一个浏览器提供的 API,用于监听元素进入或离开视口。你可以将加载更多的触发逻辑与 Intersection Observer
结合起来,当组件底部元素进入视口时触发加载更多的操作。这种方法在一些场景下能够更好地控制触发时机但需进行性能或兼容性方面的测试
1.页面中使用
1 2 3 4 5 6
| <template> <div class="scroll-container"> <!-- 组件内容 --> <div class="bottom-element" ref="bottomElement"></div> </div> </template>
|
2.mounted
中进行操作
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
| <script> export default { mounted() { const options = { root: this.$refs.bottomElement.parentElement, rootMargin: '0px', threshold: 1.0 };
const observer = new IntersectionObserver(entries => { if (entries[0].intersectionRatio === 1) { // 触发加载更多的操作 this.loadMoreData(); } }, options);
observer.observe(this.$refs.bottomElement); }, methods: { loadMoreData() { // 执行加载更多的逻辑 } } } </script>
|
6. <list>
组件(推荐)
uniapp提供了内置的 <list>
组件,可以轻松实现上拉加载更多的效果。你可以在模板中使用 <list>
标签,然后监听 @loadmore
事件来执行加载更多操作,如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| <template> <div> <list @loadmore="onLoadMore"> <!-- 列表内容 --> </list> </div> </template>
<script> export default { methods: { onLoadMore(done) { // 执行加载更多操作 // 调用 done() 表示加载完成 } } } </script>
|
7. touchstart
、touchmove
、touchend
等手势事件
如果想要自定义下拉刷新的样式和效果,可以使用 touchstart
、touchmove
、touchend
等手势事件来监听用户的下拉操作,然后实现自定义的下拉刷新效果,效果如下:
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
| <template> <div class="container" @touchstart="onTouchStart" @touchmove="onTouchMove"> <div class="content"> <!-- 列表内容 --> </div> <div class="loading" v-if="loading"> 加载中... </div> </div> </template>
<script> export default { data() { return { loading: false, startY: 0 }; }, methods: { onTouchStart(event) { this.startY = event.touches[0].clientY; }, onTouchMove(event) { const distance = event.touches[0].clientY - this.startY; if (distance > 50) { // 当滑动距离超过50时,触发加载更多 this.loadMore(); } }, loadMore() { if (!this.loading) { this.loading = true; // 模拟加载更多操作 setTimeout(() => { // 加载完成后重置loading状态 this.loading = false; // 执行加载更多的实际操作 console.log('加载更多数据'); }, 1000); } } } } </script>
<style> .container { height: 100vh; overflow: auto; }
.content { height: 1000px; /* 假设内容高度 */ }
.loading { text-align: center; padding: 10px; } </style>
|