当前位置: 首页 > article >正文

uniapp:上拉加载更多、下拉刷新、页面滚动到指定位置

提醒
本文实例是使用uniapp进行开发演示的。

一、需求场景

在开发商品(SKU)列表页面时,通常有三个需求:

  1. 页面下拉刷新,第一页展示最新数据;
  2. 上拉加载更多数据;
  3. 列表页面可以滚动到指定位置,例如:回到顶部、回到上次浏览位置

二、需求分析

  1. 接口支持分页加载
  2. 页面下拉刷新
    首先在pages.json页面路由里将enablePullDownRefresh参数值设为true,表示此页面开启下拉刷新;刷新成功后,页面数据更新并回到顶部;
  3. 页面向上滑动时,检测是否有更多数据,加载到新的数据直接显示在当前页面列表数据下方,否则提示用户没有更多数据了;
  4. 记录当前页面滚动的位置;当触发滚动到指定位置方法时将记录页面上次滚动的位置数值参入即可。

三、技术方案

  1. uni-app页面生命周期onPullDownRefresh函数,监听用户下拉动作,一般用于下拉刷新;
  2. uni-app页面生命周期onReachBottom函数,页面滚动到底部的事件(不是scroll-view滚到底),常用于下拉下一页数据。具体见下方注意事项
  3. uni-app页面生命周期onPageScroll函数,监听页面滚动,参数为Object;通过obj.scrollTop获取滚动距离;
  4. uni.pageScrollTo()方法实现页面滚动到指定位置

四、技术知识点简介

4.1 下拉刷新(onPullDownRefresh)

小程序开启下拉刷新,在配置页面(pages.json)的 enablePullDownRefresh 属性为 true。
js代码示例

{
    "pages": [
       {
					"path": "pages/list/testPulldownRefreshReachBottom",
					"style": {
						"navigationBarTitleText": "产品列表",
						"enablePullDownRefresh": true,
						"app-plus": {
							"bounce": "vertical"
						}
					}
				}
   ]
}

在 App 平台下可以自定义部分下拉刷新的配置 page->style->app-plus->pullToRefresh。
js代码示例

{
    "pages": [
        {
            "path": "pages/index/index", //首页
            "style": {
                "app-plus": {
                    "pullToRefresh": {
                        "support": true,
                        "color": "#ff3333",
                        "style": "default",
                        "contentdown": {
                            "caption": "下拉可刷新自定义文本"
                        },
                        "contentover": {
                            "caption": "释放可刷新自定义文本"
                        },
                        "contentrefresh": {
                            "caption": "正在刷新自定义文本"
                        }
                    }
                }
            }
        }
    ]
}

下拉刷新使用注意

  • enablePullDownRefresh 与 pullToRefresh->support 同时设置时,后者优先级较高。
  • 如果期望在 App 和小程序上均开启下拉刷新的话,请配置页面的 enablePullDownRefresh 属性为 true。
  • 若仅期望在 App 上开启下拉刷新,则不要配置页面的 enablePullDownRefresh 属性,而是配置 pullToRefresh->support 为 true。
  • 开启原生下拉刷新时,页面里不应该使用全屏高的scroll-view,向下拖动内容时,会优先触发下拉刷新而不是scroll-view滚动
  • 原生下拉刷新的起始位置在原生导航栏的下方,如果取消原生导航栏,使用自定义导航栏,原生下拉刷新的位置会在屏幕顶部。如果希望在自定义导航栏下方拉动,只能使用circle方式的下拉刷新,并设置offset参数,将circle圈的起始位置调整到自定义导航栏下方。hello uni-app的扩展组件中有示例。
  • 如果想在app端实现更多复杂的下拉刷新,比如美团、京东App那种拉下一个特殊图形,可以使用nvue的组件。HBuilderX 2.0.3+起,新建项目选择新闻模板可以体验
  • 如果想在vue页面通过web前端技术实现下拉刷新,插件市场有例子,但前端下拉刷新的性能不如原生,复杂长列表会很卡
  • iOS上,default模式的下拉刷新和bounce回弹是绑定的,如果设置了bounce:none,会导致无法使用default下拉刷新
4.2 页面滚动到底部的事件(onReachBottom)

可在pages.json里定义具体页面底部的触发距离onReachBottomDistance,

比如设为50,那么滚动页面到距离底部50px时,就会触发onReachBottom事件。

如使用scroll-view导致页面没有滚动,则触底事件不会被触发。scroll-view滚动到底部的事件请参考scroll-view的文档。

onReachBottomDistance 参数说明
onReachBottomDistance:Number类型,默认值 50,页面上拉触底事件触发时距页面底部距离,单位只支持px。

4.3 监听页面滚动(onPageScroll)

参数说明
scrollTop:Number类型,页面在垂直方向已滚动的距离(单位px)
js代码示例

onPageScroll : function(e) { //nvue暂不支持滚动监听,可用bindingx代替
	console.log("滚动距离为:" + e.scrollTop);
},

监听页面滚动注意

  • onPageScroll里不要写交互复杂的js,比如频繁修改页面。因为这个生命周期是在渲染层触发的,在非h5端,js是在逻辑层执行的,两层之间通信是有损耗的。如果在滚动过程中,频发触发两层之间的数据交换,可能会造成卡顿。(uvue在app端无此限制)
  • 在webview渲染时,比如app-vue、微信小程序、H5中,也可以使用wxs监听滚动,参考;在app-nvue中,可以使用bindingx监听滚动,参考。
  • 如果想实现滚动时标题栏透明渐变,在App和H5下,可在pages.json中配置titleNView下的type为transparent,参考。(uni-app x不支持)
  • 如果需要滚动吸顶固定某些元素,推荐使用css的粘性布局,参考插件市场。插件市场也有其他js实现的吸顶插件,但性能不佳,需要时可自行搜索。(uni-app x可自由在uts中设置固定位置)
4.4 uni.pageScrollTo(OBJECT)

将页面滚动到目标位置。可以指定滚动到具体的scrollTop数值,也可以指定滚动到某个元素的位置

OBJECT参数说明
在这里插入图片描述

五、实例效果图

1.第一页数据
在这里插入图片描述

2.上拉加载更多数据
在这里插入图片描述

3.下拉刷新
在这里插入图片描述

4.页面滑动超过一页显示 回到顶部按钮
在这里插入图片描述

5.上拉加载更多数据后,已经全部加载完了
在这里插入图片描述

6.点击回到顶部按钮后的页面和第一页显示的数据一样

六、实例代码

testPulldownRefreshReachBottom.vue文件代码

<template>
    <view class="content-root">
        <view class="content-wrap">
            <view v-if="productList && productList.length > 0">
                <view class="list-item" v-for="(item, index) in productList" :key="index">
                    <text class="itme-name">{{ item.name }}</text>
                    <text class="itme-desc">{{ item.desc }}</text>
                </view>
            </view>
            <view class="no-data" v-else>暂无数据</view>
            <view class="no-more-data" v-if="noMoreData">
                <text>没有更多数据了</text>
            </view>
        </view>
        <view class="go-top" v-if="showGoToTop" @click="goToTop">
            <text>回到</text>
            <text>顶部</text>
        </view>
    </view>

</template>
<script>
export default {
    data() {
        return {
            productType: 1,
            currentPage: 1,
            lastPage: 1,
            lastPostion: 0,
            pageSize: 30,
            total: 0,
            noMoreData: false,
            productList: [],
            showGoToTop: false
        }
    },

    onLoad(option) {
        this.productType = option.productType
        this.getProductList(true)
    },

    onPageScroll(e) {
        this.lastPostion = e.scrollTop
        console.log(`当前滚动位置 this.lastPostion = ${this.lastPostion} , this.showGoToTop = ${this.showGoToTop}`)
        if (this.lastPostion > 300) {
            this.showGoToTop = true
        } else if (this.showGoToTop) {
            this.showGoToTop = false
        }
    },

    onPullDownRefresh() {
        this.lastPage = this.currentPage
        this.currentPage = 1
        this.getProductList(true)
        setTimeout(() => {
            uni.stopPullDownRefresh()
        }, 600);
    },

    onReachBottom() {
        if (this.noMoreData) {
            return
        }
        this.lastPage = this.currentPage
        this.currentPage++
        this.getProductList(false)
    },

    methods: {
        //回到顶部
        goToTop() {
            uni.pageScrollTo({
                scrollTop: 0,
                duration: 0,
            })
        },

        //获取商品列表
        async getProductList(refresh) {
            //let result =  await getProductList() // 网络请求

            setTimeout(() => {// 模拟网络请求
                if (refresh) {
                    this.iniLocalData()
                    return
                }

                this.loadMoreData()

            }, 500);
        },

        iniLocalData() {
            this.noMoreData = false
            this.productList = [
                {
                    productId: "1234567890",
                    name: "西蓝花",
                    desc: "有机蔬菜,安全健康",
                    skuType: [
                        {
                            id: "1",
                            price: "9.99",
                            txt: ""
                        }
                    ]
                },
                {
                    productId: "3234567890",
                    name: "西红柿",
                    desc: "有机蔬菜,安全健康;",
                    skuType: [
                        {
                            id: "1",
                            price: "9.00",
                            txt: ""
                        }
                    ]
                },
                {
                    productId: "4234567890",
                    name: "洋葱",
                    desc: "洋葱可生吃,安全健康;",
                    skuType: [
                        {
                            id: "1",
                            price: "5.00",
                            txt: ""
                        }
                    ]
                },
                {
                    productId: "1734567890",
                    name: "小青菜",
                    desc: "有机蔬菜,安全健康;",
                    skuType: [
                        {
                            id: "1",
                            price: "3.00",
                            txt: ""
                        }
                    ]
                },
                {
                    productId: "1234467890",
                    name: "上海青",
                    desc: "蔬菜,安全健康;",
                    skuType: [
                        {
                            id: "1",
                            price: "3.00",
                            txt: ""
                        }
                    ]
                },
                {
                    productId: "1234567390",
                    name: "上海青",
                    desc: "蔬菜,安全健康;",
                    skuType: [
                        {
                            id: "1",
                            price: "3.00",
                            txt: ""
                        }
                    ]
                },
                {
                    productId: "1239567390",
                    name: "娃娃菜",
                    desc: "蔬菜,安全健康;",
                    skuType: [
                        {
                            id: "1",
                            price: "8.00",
                            txt: ""
                        }
                    ]
                },
                {
                    productId: "1239567390",
                    name: "胡萝卜",
                    desc: "有机蔬菜,安全健康;",
                    skuType: [
                        {
                            id: "1",
                            price: "5.00",
                            txt: ""
                        }
                    ]
                },
                {
                    productId: "1239567390",
                    name: "西葫芦",
                    desc: "蔬菜,安全健康;",
                    skuType: [
                        {
                            id: "1",
                            price: "8.00",
                            txt: ""
                        }
                    ]
                },
                {
                    productId: "1239567390",
                    name: "紫甘蓝",
                    desc: "蔬菜,安全健康;",
                    skuType: [
                        {
                            id: "1",
                            price: "5.00",
                            txt: ""
                        }
                    ]
                },
                {
                    productId: "1239567390",
                    name: "大白菜",
                    desc: "蔬菜,安全健康;",
                    skuType: [
                        {
                            id: "1",
                            price: "3.00",
                            txt: ""
                        }
                    ]
                }
            ]
        },

        loadMoreData() {
            if (this.noMoreData) {
                return
            }
            let result = [
                {
                    productId: "2239567390",
                    name: "牛腱",
                    desc: "新鲜牛肉;",
                    skuType: [
                        {
                            id: "1",
                            price: "109.00",
                            txt: ""
                        }
                    ]
                },
                {
                    productId: "2239567391",
                    name: "牛腿肉",
                    desc: "新鲜牛肉;",
                    skuType: [
                        {
                            id: "1",
                            price: "99.00",
                            txt: ""
                        }
                    ]
                },
                {
                    productId: "2239567392",
                    name: "牛腩",
                    desc: "新鲜牛肉;",
                    skuType: [
                        {
                            id: "1",
                            price: "89.00",
                            txt: ""
                        }
                    ]
                },
                {
                    productId: "2339567390",
                    name: "排骨",
                    desc: "新鲜猪肉;",
                    skuType: [
                        {
                            id: "1",
                            price: "29.00",
                            txt: ""
                        }
                    ]
                },
                {
                    productId: "2339567391",
                    name: "后退肉",
                    desc: "新鲜猪肉;",
                    skuType: [
                        {
                            id: "1",
                            price: "18.00",
                            txt: ""
                        }
                    ]
                },
                {
                    productId: "2339567390",
                    name: "五花肉",
                    desc: "新鲜猪肉;",
                    skuType: [
                        {
                            id: "1",
                            price: "24.00",
                            txt: ""
                        }
                    ]
                }
            ]

            this.productList = [...this.productList, ...result]
            this.noMoreData = true // 这个逻辑在实际项目开发中以接口返回的总数量为准
        }
    }

}
</script>

<style scoped>
.content-root {
    height: 100%;
    background-color: #f5f5f5;
    padding: 32rpx;
}

.content-wrap {
    background-color: #f5f5f5;
    padding-bottom: 80rpx;
}

.list-item {
    display: flex;
    padding: 16rpx 20rpx;
    flex-direction: column;
    background-color: #ffffff;
    border-radius: 16rpx;
    color: #000;
    margin-bottom: 32rpx;
}

.itme-name {
    font-size: 32rpx;
}

.itme-desc {
    font-size: 24rpx;
}

.no-data {
    height: 100%;
    text-align: center;
    margin-top: 400rpx;
    color: #000;
    font-size: 28rpx;
}

.no-more-data {
    width: 100%;
    height: 50rpx;
    color: #000;
    align-items: center;
    font-size: 28rpx;
    font-family: PingFangSC-Medium, PingFang SC;
    text-align: center;
}

.go-top {
    z-index: 99;
    position: fixed;
    display: flex;
    flex-flow: column;
    right: 0;
    bottom: 0;
    margin-right: 32rpx;
    margin-bottom: 200rpx;
    width: 80rpx;
    height: 80rpx;
    align-items: center;
    background-color: #eeeeee;
    border-radius: 50%;
    font-size: 20rpx;
    font-family: PingFangSC-Medium, PingFang SC;
    text-align: center;
}
</style>

http://www.kler.cn/news/366294.html

相关文章:

  • 基于行业分类的目标检测与跟踪系统
  • 实现vuex源码,手写
  • 任务看板是什么?如何选择合适的任务看板工具?
  • 【Android】Convenient ADB Commands
  • 开源vGPU方案 HAMi实现细粒度GPU切分——筑梦之路
  • 庐阳区2023年信息学竞赛试题
  • ArcGIS必会的选择要素方法(AND、OR、R、IN等)位置选择等
  • 讲解 SpringMVC 中数据绑定的实现方式
  • K8S配置storage-class
  • linux-fslc 与 linux-imx
  • 每日“亿“题 东方博宜OJ 1541 - 小 X 学游泳(swim)
  • 什么是HarmonyOS元服务?
  • Pytest-Bdd-Playwright 系列教程(2):支持在多浏览器、多环境中执行测试
  • Excel做数据匹配
  • QT界面开发:图形化设计、资源文件添加
  • python+Mosh网课笔记13 使用Python进行机器学习
  • 对Kotlin在Android开发中的应用看法
  • Django模板的使用
  • w~自动驾驶合集7
  • Photoshop中的混合模式公式详解
  • GitLab+Jenkins 实现 Webhook 自动化触发构建
  • 聚观早报 | 谷歌重组AI部门;荣耀Magic 7标准版外观细节
  • # 渗透测试#安全见闻9 二进制安全
  • es中自定义ik的分词词库(词库布置在nginx)
  • 浪潮云启操作系统(InLinux)bcache缓存实践:理解OpenStack环境下虚拟机卷、Ceph OSD、bcache设备之间的映射关系
  • 莱维飞行(Levy Flight)机制的介绍和MATLAB例程