概述
基于小程序开发的列表加载更多例子。
详细
代码下载:
一、前言
基于小程序开发的列表加载更多例子。
二、运行效果
运行效果(演示的小视频,点击播放即可)
三、实现过程
总体思路如何:
1、通过scroll-view组件提供的bindscroll方法监控滚动的时候是否距离底部在40px内,如果小于40px则触发加载更多方法(见完整代码index.js里的bindscroll方法)
2、通过使用发现很多时候服务返回数据太快了,没有加载等待的过程,显的不自然,所以在loadMore方法里通过setTimeout来保证至少有333毫秒的加载时间(见完整代码index.js里的loadMore方法)
3、实际使用中又发现一个问题,上滑到底部会重复触发加载更多方法导致重复的网络请求。通过记录上次加载时间lastRequestTime,保证两次网络请求的间隔大于1秒(见完整代码index.js里的fetchList方法),这样就能避免重复调用加载更多的问题
备注:demo代码里的网络请求wx.requestTest方法是为了显示效果,所以写了个模拟的请求方法,实际使用可替换为wx.request对接自己项目的服务
具体实现如下:
1、创建小程序,点击下图里框起来的位置,创建小程序
2、在app.js里添加网络模拟方法
let serverData = [];for(let i = 1; i < 25; i++){ serverData.push({id:i, name:i})}App({ onLaunch: function () { wx.requestTest = ({data:{page,size},success}) => { setTimeout( () => { //模拟网络返回请求 let res = { data:{ data:{ rows: serverData.slice((page - 1) * size, size + (page - 1) * size) }, result: true, } } console.log(res) success(res) },1000//模拟网络延迟 ) } }, globalData: { }})
3、增加和pages同层级的components文件夹,在里面创建Loading文件夹,并在下面创建以下文件
//loading.jsComponent({ data: { }, properties: { visible: {//loading效果是否显示 type: Boolean, value: false//默认不显示 }, },})//loading.json{ "component": true,//表示是组件 "usingComponents": {}}//loading.wxss.loadmore { width: 100%; height: 0rpx; display: flex; align-items: center; justify-content: center; padding-top:24rpx; transition: all 200ms linear;}.loadmore.visible { height: 80rpx;}.my-loading:after { content: " "; display: block; width: 26px; height: 26px; margin: 1px; border-radius: 50%; border: 2px solid #FFD800; border-color: #fff transparent #FFD800 transparent; animation: lds-dual-ring 1.2s linear infinite;}@keyframes lds-dual-ring { 0% { transform: rotate(0deg); } 100% { transform: rotate(360deg); }}//loading.wxml
4、修改pages/index文件夹下各文件如下
//index.json{ "navigationBarTitleText": "首页", "usingComponents": { "loading": "/components/Loading/loading"//引用组件 }}//index.jsconst app = getApp()let loadingMore = falselet lastScollTop = 0;let lastRequestTime = 0;Page({ data: { list: [], hasMore: true,//列表是否有数据未加载 page: 1, size: 8,//每页8条数据 scrollYHeight: 0,//scroll-view高度 }, bindscroll: function (e) { const { scrollHeight, scrollTop } = e.detail; const { scrollYHeight, hasMore } = this.data; //如果当前没有加载中且列表还有数据未加载,且页面滚动到距离底部40px内 if (!loadingMore && hasMore && (scrollHeight - scrollYHeight - scrollTop < 40) && lastScollTop <= scrollTop) { this.loadMore() } lastScollTop = scrollTop }, loadMore: function () { const { page, hasMore } = this.data; if (!hasMore || loadingMore) return; loadingMore = true setTimeout( () => { this.fetchList(page + 1, () => { loadingMore = false; }) }, 333 ) }, fetchList: function (page, cb) { let nowRequestTime = (new Date()).getTime(); //限制两次网络请求间隔至少1秒 if (nowRequestTime - lastRequestTime < 1000) { if (cb) cb(); return; } lastRequestTime = nowRequestTime //这里wx.requestTest实际使用时换成wx.request //wx.requestTest定义见app.js wx.requestTest({ url: "testUrl", header: { 'Authorization': wx.getStorageSync('token') }, data: { page, size: this.data.size, }, success: (res) => { if (res.data && res.data.result) { let list = res.data.data.rows || []; if (list.length == 0) { this.setData({ hasMore: false, page, }) } else { this.setData({ list: this.data.list.concat(list), hasMore: list.length == this.data.size, page, }) } } else { wx.showToast({ title: res.data ? res.data.message : "列表加载失败", icon: 'none', duration: 1000 }) } if (cb) { cb() } }, fail: () => { wx.showToast({ title: "列表加载失败", icon: 'none', duration: 1000 }) if (cb) { cb() } } }) }, onReady: function () { wx.getSystemInfo({ success: ({ windowHeight }) => { this.setData({ scrollYHeight: windowHeight })//设置scrill-view组件的高度为屏幕高度 } }) }, onLoad: function () { this.fetchList(1)//加载第一页数据 }})//index.wxml//index.css.item { width: 750rpx; height: 200rpx; font-size: 40rpx; color: black; position: relative; display: flex; align-items: center; justify-content: center;}.item::after{ content: ""; position: absolute; left: 0; right: 0; bottom: 0; border-bottom: 1rpx solid #eeeeee;} { {item.name}}
此时运行程序,可查看效果。
整体代码:
//index.jsconst app = getApp()let loadingMore = falselet lastScollTop = 0;let lastRequestTime = 0;Page({ data: { list: [], hasMore: true,//是否有数据未加载 page: 1, size: 8, scrollYHeight: 0, }, bindscroll: function (e) { const { scrollHeight, scrollTop } = e.detail; const { scrollYHeight, hasMore } = this.data; //如果当前没有加载中且列表还有数据未加载,且页面滚动到距离底部40px内 if (!loadingMore && hasMore && (scrollHeight - scrollYHeight - scrollTop < 40) && lastScollTop <= scrollTop) { this.loadMore() } lastScollTop = scrollTop }, loadMore: function () { const { page, hasMore } = this.data; if (!hasMore || loadingMore) return; loadingMore = true setTimeout( () => { this.fetchList(page + 1, () => { loadingMore = false; }) }, 333 ) }, fetchList: function (page, cb) { let nowRequestTime = (new Date()).getTime(); if (nowRequestTime - lastRequestTime < 1000) { if (cb) cb(); return; } lastRequestTime = nowRequestTime //这里wx.requestTest实际使用时换成wx.request //wx.requestTest定义见app.js wx.requestTest({ url: "testUrl", header: { 'Authorization': wx.getStorageSync('token') }, data: { page, size: this.data.size, }, success: (res) => { if (res.data && res.data.result) { let list = res.data.data.rows || []; if (list.length == 0) { if(page == 1){ this.setData({ hasMore: false, page, list: [] }) }else { this.setData({ hasMore: false, page, }) } } else { this.setData({ list: this.data.list.concat(list), hasMore: list.length == this.data.size, page, }) } } else { wx.showToast({ title: res.data ? res.data.message : "列表加载失败", icon: 'none', duration: 1000 }) } if (cb) { cb() } }, fail: () => { wx.showToast({ title: "列表加载失败", icon: 'none', duration: 1000 }) if (cb) { cb() } } }) }, onReady: function () { const { windowWidth, ratio } = app.globalData wx.getSystemInfo({ success: ({ windowHeight, pixelRatio }) => { this.setData({ scrollYHeight: windowHeight }) } }) }, onLoad: function () { this.fetchList(1) }})//index.wxml//index.css.item { width: 750rpx; height: 200rpx; font-size: 40rpx; color: black; position: relative; display: flex; align-items: center; justify-content: center;}.item::after{ content: ""; position: absolute; left: 0; right: 0; bottom: 0; border-bottom: 1rpx solid #eeeeee;}//app.jslet serverData = [];for(let i = 1; i < 25; i++){ serverData.push({id:i, name:i})}App({ onLaunch: function () { wx.requestTest = ({data:{page,size},success}) => { setTimeout( () => { //模拟网络返回请求 let res = { data:{ data:{ rows: serverData.slice((page - 1) * size, size + (page - 1) * size) }, result: true, } } console.log(res) success(res) },1000//模拟网络延迟 ) } }, globalData: { }}) { {item.name}}
三、项目结构
四、其他补充
暂时没有