微信小程序列表加载更多
概述
基于小程序开发的列表加载更多例子。
详细
一、前言
基于小程序开发的列表加载更多例子。
二、运行效果
运行效果(演示的小视频,点击播放即可)
三、实现过程
总体思路如何:
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维:就是矩…...
深入浅出Asp.Net Core MVC应用开发系列-AspNetCore中的日志记录
ASP.NET Core 是一个跨平台的开源框架,用于在 Windows、macOS 或 Linux 上生成基于云的新式 Web 应用。 ASP.NET Core 中的日志记录 .NET 通过 ILogger API 支持高性能结构化日志记录,以帮助监视应用程序行为和诊断问题。 可以通过配置不同的记录提供程…...
stm32G473的flash模式是单bank还是双bank?
今天突然有人stm32G473的flash模式是单bank还是双bank?由于时间太久,我真忘记了。搜搜发现,还真有人和我一样。见下面的链接:https://shequ.stmicroelectronics.cn/forum.php?modviewthread&tid644563 根据STM32G4系列参考手…...
基于FPGA的PID算法学习———实现PID比例控制算法
基于FPGA的PID算法学习 前言一、PID算法分析二、PID仿真分析1. PID代码2.PI代码3.P代码4.顶层5.测试文件6.仿真波形 总结 前言 学习内容:参考网站: PID算法控制 PID即:Proportional(比例)、Integral(积分&…...
2023赣州旅游投资集团
单选题 1.“不登高山,不知天之高也;不临深溪,不知地之厚也。”这句话说明_____。 A、人的意识具有创造性 B、人的认识是独立于实践之外的 C、实践在认识过程中具有决定作用 D、人的一切知识都是从直接经验中获得的 参考答案: C 本题解…...
云原生玩法三问:构建自定义开发环境
云原生玩法三问:构建自定义开发环境 引言 临时运维一个古董项目,无文档,无环境,无交接人,俗称三无。 运行设备的环境老,本地环境版本高,ssh不过去。正好最近对 腾讯出品的云原生 cnb 感兴趣&…...
AGain DB和倍数增益的关系
我在设置一款索尼CMOS芯片时,Again增益0db变化为6DB,画面的变化只有2倍DN的增益,比如10变为20。 这与dB和线性增益的关系以及传感器处理流程有关。以下是具体原因分析: 1. dB与线性增益的换算关系 6dB对应的理论线性增益应为&…...
省略号和可变参数模板
本文主要介绍如何展开可变参数的参数包 1.C语言的va_list展开可变参数 #include <iostream> #include <cstdarg>void printNumbers(int count, ...) {// 声明va_list类型的变量va_list args;// 使用va_start将可变参数写入变量argsva_start(args, count);for (in…...
stm32wle5 lpuart DMA数据不接收
配置波特率9600时,需要使用外部低速晶振...
渗透实战PortSwigger靶场:lab13存储型DOM XSS详解
进来是需要留言的,先用做简单的 html 标签测试 发现面的</h1>不见了 数据包中找到了一个loadCommentsWithVulnerableEscapeHtml.js 他是把用户输入的<>进行 html 编码,输入的<>当成字符串处理回显到页面中,看来只是把用户输…...
水泥厂自动化升级利器:Devicenet转Modbus rtu协议转换网关
在水泥厂的生产流程中,工业自动化网关起着至关重要的作用,尤其是JH-DVN-RTU疆鸿智能Devicenet转Modbus rtu协议转换网关,为水泥厂实现高效生产与精准控制提供了有力支持。 水泥厂设备众多,其中不少设备采用Devicenet协议。Devicen…...
