微信小程序列表加载更多
概述
基于小程序开发的列表加载更多例子。
详细
一、前言
基于小程序开发的列表加载更多例子。
二、运行效果
运行效果(演示的小视频,点击播放即可)
三、实现过程
总体思路如何:
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维:就是矩…...
Vue记事本应用实现教程
文章目录 1. 项目介绍2. 开发环境准备3. 设计应用界面4. 创建Vue实例和数据模型5. 实现记事本功能5.1 添加新记事项5.2 删除记事项5.3 清空所有记事 6. 添加样式7. 功能扩展:显示创建时间8. 功能扩展:记事项搜索9. 完整代码10. Vue知识点解析10.1 数据绑…...
基于ASP.NET+ SQL Server实现(Web)医院信息管理系统
医院信息管理系统 1. 课程设计内容 在 visual studio 2017 平台上,开发一个“医院信息管理系统”Web 程序。 2. 课程设计目的 综合运用 c#.net 知识,在 vs 2017 平台上,进行 ASP.NET 应用程序和简易网站的开发;初步熟悉开发一…...
C++中string流知识详解和示例
一、概览与类体系 C 提供三种基于内存字符串的流,定义在 <sstream> 中: std::istringstream:输入流,从已有字符串中读取并解析。std::ostringstream:输出流,向内部缓冲区写入内容,最终取…...
在QWebEngineView上实现鼠标、触摸等事件捕获的解决方案
这个问题我看其他博主也写了,要么要会员、要么写的乱七八糟。这里我整理一下,把问题说清楚并且给出代码,拿去用就行,照着葫芦画瓢。 问题 在继承QWebEngineView后,重写mousePressEvent或event函数无法捕获鼠标按下事…...
iOS性能调优实战:借助克魔(KeyMob)与常用工具深度洞察App瓶颈
在日常iOS开发过程中,性能问题往往是最令人头疼的一类Bug。尤其是在App上线前的压测阶段或是处理用户反馈的高发期,开发者往往需要面对卡顿、崩溃、能耗异常、日志混乱等一系列问题。这些问题表面上看似偶发,但背后往往隐藏着系统资源调度不当…...
Webpack性能优化:构建速度与体积优化策略
一、构建速度优化 1、升级Webpack和Node.js 优化效果:Webpack 4比Webpack 3构建时间降低60%-98%。原因: V8引擎优化(for of替代forEach、Map/Set替代Object)。默认使用更快的md4哈希算法。AST直接从Loa…...
Ubuntu系统复制(U盘-电脑硬盘)
所需环境 电脑自带硬盘:1块 (1T) U盘1:Ubuntu系统引导盘(用于“U盘2”复制到“电脑自带硬盘”) U盘2:Ubuntu系统盘(1T,用于被复制) !!!建议“电脑…...
水泥厂自动化升级利器:Devicenet转Modbus rtu协议转换网关
在水泥厂的生产流程中,工业自动化网关起着至关重要的作用,尤其是JH-DVN-RTU疆鸿智能Devicenet转Modbus rtu协议转换网关,为水泥厂实现高效生产与精准控制提供了有力支持。 水泥厂设备众多,其中不少设备采用Devicenet协议。Devicen…...
【安全篇】金刚不坏之身:整合 Spring Security + JWT 实现无状态认证与授权
摘要 本文是《Spring Boot 实战派》系列的第四篇。我们将直面所有 Web 应用都无法回避的核心问题:安全。文章将详细阐述认证(Authentication) 与授权(Authorization的核心概念,对比传统 Session-Cookie 与现代 JWT(JS…...
如何在Windows本机安装Python并确保与Python.NET兼容
✅作者简介:2022年博客新星 第八。热爱国学的Java后端开发者,修心和技术同步精进。 🍎个人主页:Java Fans的博客 🍊个人信条:不迁怒,不贰过。小知识,大智慧。 💞当前专栏…...
