微信小程序列表加载更多
概述
基于小程序开发的列表加载更多例子。
详细
一、前言
基于小程序开发的列表加载更多例子。
二、运行效果
运行效果(演示的小视频,点击播放即可)
三、实现过程
总体思路如何:
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.js
Component({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
<view class="loadmore {{visible && 'visible'}}"><view class="my-loading" wx:if="{{visible}}"></view>
</view>
4、修改pages/index文件夹下各文件如下
//index.json
{"navigationBarTitleText": "首页","usingComponents": {"loading": "/components/Loading/loading"//引用组件}
}
//index.js
const app = getApp()
let loadingMore = false
let 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 = truesetTimeout(() => {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.jswx.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
<scroll-view scroll-y style="height:{{scrollYHeight}}px" scroll-top="{{scrollTop}}" bindscroll="bindscroll"><viewclass="item"wx:for="{{list}}"wx:key="id"wx:for-index="idx">{{item.name}}</view><loading visible="{{hasMore}}"></loading>
</scroll-view>
//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;
}
此时运行程序,可查看效果。
整体代码:
//index.js
const app = getApp()
let loadingMore = false
let 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 = truesetTimeout(() => {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.jswx.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.globalDatawx.getSystemInfo({success: ({ windowHeight, pixelRatio }) => {this.setData({ scrollYHeight: windowHeight })}})},onLoad: function () {this.fetchList(1)}
})//index.wxml
<scroll-view scroll-y style="height:{{scrollYHeight}}px" scroll-top="{{scrollTop}}" bindscroll="bindscroll"><viewclass="item"wx:for="{{list}}"wx:key="id"wx:for-index="idx">{{item.name}}</view><loading visible="{{hasMore}}"></loading>
</scroll-view>//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.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: {}
})
三、项目结构

四、其他补充
暂时没有
相关文章:
微信小程序列表加载更多
概述 基于小程序开发的列表加载更多例子。 详细 一、前言 基于小程序开发的列表加载更多例子。 二、运行效果 运行效果(演示的小视频,点击播放即可) 三、实现过程 总体思路如何: 1、通过scroll-view组件提供的bindscroll方法…...
数据库知识
怎么做 常见的数据库 Oracle Mysql SOLSever Navicat (新版可以链接mysql oracle) http://sqlfiddle.com/ 数据库操作在线练习 mysql自带四个数据库 数据库语言的使用 显示数据库:show databases; 创建数据库:…...
VUE 目录介绍
更新升级(npm - i)之后最终目录如下: total 1672 drwxr-xr-x 18 testrose staff 576 8 22 02:53 . drwxr-xr-x 24 testrose staff 768 8 22 02:50 .. -rw-r--r-- 1 testrose staff 402 8 22 02:52 .babelrc -rw…...
Selenium的基本使用
文章目录 引入一.选择元素的基本方法1.根据id 选择元素2.根据 class属性选择元素当元素有 多个class类型 时 3.根据 tag名 选择元素4.通过WebElement对象选择元素5.find_element 和 find_elements 的区别 二.等待界面元素出现1.隐式等待2.显示等待 三.操控元素的基本方法1.点击…...
数据结构-----树的易错点
1.树的度和m叉树 •度为m的树(度表示该结点有多少个孩子(分支)) 任意结点的度<m(最多m个孩子) 至少又一个结点度m(有m个孩子) 一定是非空树,至少有m1个结点 •m叉树 任意结点的度<m(最多有m个孩子) 允许所…...
写之前的项目关于使用git remote -v 找不到项目地址的解决方案
提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档 文章目录 一、报错解析1. 报错内容2. 报错翻译3. 报错解析(1)使用git branch来查看git仓库有几个分支(2)使用git remote -v&am…...
STM32 F103C8T6学习笔记9:0.96寸单色OLED显示屏—自由取模显示—显示汉字与图片
今日学习0.96寸单色OLED显示屏的自由取模显示: 宋体汉字比较复杂,常用字符可以直接复制存下来,毕竟只有那么几十个字母字符,但汉字实在太多了,基本不会全部放在单片机里存着,一般用到多少个字就取几个字的模ÿ…...
直播平台源码搭建协议讲解篇:传输控制协议TCP
简介: 由于直播平台在当今时代发展的越来越迅速,使得直播平台的技术功能越来越智能,让用户在直播平台中能够和其他用户进行实时互动,让用户可以获取到全世界最新的资讯,让一些用户可以作为主播获得工作,让…...
中文编码问题:raw_input输入、文件读取、变量比较等str、unicode、utf-8转换问题
最近研究搜索引擎、知识图谱和Python爬虫比较多,中文乱码问题再次浮现于眼前。虽然市面上讲述中文编码问题的文章数不胜数,同时以前我也讲述过PHP处理数据库服务器中文乱码问题,但是此处还是准备简单做下笔记。方便以后查阅和大家学习。 …...
基于Jenkins自动打包并部署Tomcat环境
目录 1、配置git主机 2、配置jenkins主机 3、配置web主机 4、新建Maven项目 5、验证 Jenkins 自动打包部署结果 Jenkins 的工作原理是先将源代码从 SVN/Git 版本控制系统中拷贝一份到本地,然后根据设置的脚本调用Maven进行 build(构建)。…...
开利网络受邀参与御盛马术庄园发展专委会主题会议
近日,开利网络受邀参与深度合作客户御盛马术庄园组织的首届发展专委会主体会议,就马术庄园发展方向进行沟通,数字化也是重要议题之一。目前,御盛马术庄园已经完成数字化系统的初步搭建,将通过线上线下相结合的方式搭建…...
无类别域间路由(Classless Inter-Domain Routing, CIDR):理解IP网络和子网划分(传统的IP地址类ABCDE:分类网络)
文章目录 无类别域间路由(CIDR):理解IP网络和子网划分引言传统的IP地址类关于“IP地址的浪费” IP地址与CIDRIP地址概述网络号与主机号CIDR记法(网络 网络地址/子网掩码)网络和广播地址 CIDR的优势减少路由表项缓解IP…...
合宙Air724UG LuatOS-Air LVGL API-概念
概念 在 LVGL 中,用户界面的基本构建块是对象。例如,按钮,标签,图像,列表,图表或文本区域。 属性 基本属性 所有对象类型都共享一些基本属性: Position (位置) Size (尺寸) Parent (父母) Cli…...
【C语言】位段,枚举和联合体详解
目录 1.位段 1.1 什么是位段 1.2 位段的内存分配 1.3 位段的跨平台问题 2.枚举 2.1 枚举类型的定义 2.2 枚举的优点 3. 联合(共用体) 3.1 联合类型的定义 3.2 联合的特点 3.3 联合大小的计算 1.位段 1.1 什么是位段 位段的声明和结构体是类…...
python学习-文件管理
文件管理 shutil 文件拷贝 shutil.copy(src,dst) 注:srcrE:\python\.vscode\文件操作 windows上运行时候,如果不加r,上述文件路径在代码运行时会报错,因为其会先将双引号”“去掉,然后系统看到了文件路径中有\nc&…...
【LeetCode 算法】Number of Ways of Cutting a Pizza 切披萨的方案数-记忆化
文章目录 Number of Ways of Cutting a Pizza 切披萨的方案数问题描述:分析代码递归 Tag Number of Ways of Cutting a Pizza 切披萨的方案数 问题描述: 给你一个 rows x cols 大小的矩形披萨和一个整数 k ,矩形包含两种字符: A…...
机器视觉之光流
光流(Optical Flow)是计算机视觉领域的一个重要概念,用于描述图像中物体的运动模式。光流可以用来跟踪图像中物体的运动,检测运动中的物体,或者在机器视觉任务中估计物体的速度和位移。 光流的基本思想是根据图像像素…...
C++:list使用以及模拟实现
list使用以及模拟实现 list介绍list常用接口1.构造2.迭代器3.容量4.访问数据5.增删查改6.迭代器失效 list模拟实现1.迭代器的实现2.完整代码 list介绍 list是一个类模板,加<类型>实例化才是具体的类。list是可以在任意位置进行插入和删除的序列式容器。list的…...
深度学习基础知识-pytorch数据基本操作
1.深度学习基础知识 1.1 数据操作 1.1.1 数据结构 机器学习和神经网络的主要数据结构,例如 0维:叫标量,代表一个类别,如1.0 1维:代表一个特征向量。如 [1.0,2,7,3.4] 2维:就是矩…...
基于FPGA的智能车牌识别系统Verilog代码详解:含OV5640图像采集与HDMI显示功能...
基于FPGA的车牌识别系统verilog代码,包含verilog仿真代码,matlab仿真 OV5640采集图像,HDMI显示图像,车牌字符显示在车牌左上角,并且把车牌用红框框起。 正点原子达芬奇或者达芬奇pro都可以直接使用,fpga芯片…...
Gun.js数据验证终极指南:确保实时数据准确性的5大策略
Gun.js数据验证终极指南:确保实时数据准确性的5大策略 【免费下载链接】gun amark/gun: 是一个用于实现实时数据同步和通信的 JavaScript 库,可以方便地在 Web 应用中实现实时数据同步和通信。适合对 JavaScript、实时数据同步和想要实现实时数据同步的开…...
如何永久保存微信聊天记录:WeChatExporter完整解决方案
如何永久保存微信聊天记录:WeChatExporter完整解决方案 【免费下载链接】WeChatExporter 一个可以快速导出、查看你的微信聊天记录的工具 项目地址: https://gitcode.com/gh_mirrors/wec/WeChatExporter 你是否曾因手机丢失、系统升级或误操作而丢失珍贵的微…...
最全|OpenClaw 2026年阿里云部署方法,小白7分钟掌握
最全|OpenClaw 2026年阿里云部署方法,小白7分钟掌握。本文面向零基础用户,完整说明在轻量服务器与本地Windows11、macOS、Linux系统中部署OpenClaw(Clawdbot)的流程,包含环境配置、服务启动、Skills集成、阿…...
毕设「零焦虑」实测:paperzz 四步流水线,把本科毕业论文从 0 写到 12000 字
Paperzz-AI官网免费论文查重复率AIGC检测/开题报告/文献综述/论文初稿/期刊论文paperzz - 毕业论文-AIGC论文检测-AI智能降重-ai智能写作https://www.paperzz.cc/dissertation 谁本科毕设没陷入过「选题卡壳→文献凑数→框架乱套→格式崩溃」的死循环?对着万字要求…...
ARM64虚拟化实战:从零搭建KVM环境并理解VHE特性
ARM64虚拟化实战:从零搭建KVM环境并深度解析VHE特性 开篇:为什么ARM64虚拟化值得关注? 在云计算和边缘计算迅猛发展的今天,ARM架构凭借其出色的能效比和可扩展性,正逐步蚕食传统x86服务器市场。根据最新行业报告&#…...
云端存储本地化革新:从0到1掌握s3fs-fuse文件系统映射技术
云端存储本地化革新:从0到1掌握s3fs-fuse文件系统映射技术 【免费下载链接】s3fs-fuse FUSE-based file system backed by Amazon S3 项目地址: https://gitcode.com/gh_mirrors/s3/s3fs-fuse 在云计算时代,如何让云端存储像本地硬盘一样便捷访问…...
为什么92%的FastAPI AI服务仍在用阻塞式响应?(深度剖析async def vs sync def在LLM流式场景下的内存泄漏与协程死锁)
第一章:FastAPI 2.0异步AI流式响应的核心价值与演进脉络在大模型服务规模化部署的背景下,传统同步HTTP响应已难以满足低延迟、高吞吐、用户体验敏感的AI交互场景。FastAPI 2.0通过深度整合Python 3.11原生异步运行时、优化ASGI中间件栈及重构StreamingRe…...
UE5开发者必备:10个免费3D模型资源网站推荐(含避坑指南)
UE5开发者必备:10个免费3D模型资源网站深度评测与实战指南 当你深夜盯着UE5编辑器里那个孤零零的默认立方体发呆时,是否也经历过这种绝望?作为经历过上百个原型项目的老司机,我深刻理解优质3D资源对开发效率的致命影响。市面上90…...
OpenClaw模型热切换:GLM-4.7-Flash与Qwen3-32B的任务适配对比
OpenClaw模型热切换:GLM-4.7-Flash与Qwen3-32B的任务适配对比 1. 为什么需要模型热切换 上周我在用OpenClaw处理一个复杂的文件整理任务时,遇到了一个典型问题:Qwen3-32B模型虽然能给出高质量的文件分类建议,但每个决策都要消耗…...
