微信小程序列表加载更多

news2024/11/25 4:28:53

概述

基于小程序开发的列表加载更多例子。

详细

一、前言

基于小程序开发的列表加载更多例子。

二、运行效果

运行效果(演示的小视频,点击播放即可)

三、实现过程

总体思路如何:

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、创建小程序,点击下图里框起来的位置,创建小程序

image.png

image.png

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 = 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
<scroll-view scroll-y style="height:{{scrollYHeight}}px"   scroll-top="{{scrollTop}}" bindscroll="bindscroll">
    <view
      class="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 = 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
<scroll-view scroll-y style="height:{{scrollYHeight}}px"   scroll-top="{{scrollTop}}" bindscroll="bindscroll">
    <view
      class="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: {
  }
})

三、项目结构

WX20180719-134632@2x.png



  •  

四、其他补充

暂时没有

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/912963.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Blazor 依赖注入妙用:巧设回调

文章目录 前言依赖注入特性需求解决方案示意图 前言 依赖注入我之前写过一篇文章&#xff0c;没看过的可以看看这个。 C# Blazor 学习笔记(10):依赖注入 依赖注入特性 只能Razor组件中注入所有Razor组件在作用域注入的都是同一个依赖。作用域可以看看我之前的文章。 需求 …

【Visual Studio】生成.i文件

环境 VS版本&#xff1a;VS2013 问题 如何生成.i预编译文件&#xff1f; 步骤 1、打开VS项目属性&#xff0c;打开C/C\预处理器页面&#xff0c;【预处理到文件】选择是&#xff0c;开启。 2、生成文件如下。 3、正常编译需要关闭此选项。

ProtoBuf3语法详解

目录&#xff1a; 需求&#xff1a;字段规则消息类型的定义与使用通讯录2.0的写⼊实现TestRead.java(通讯录2.0)TestRead.java(通讯录2.0) 另⼀种验证⽅法--toString()enum类型升级通讯录⾄2.1版本Any类型oneof类型map类型默认值更新消息保留字段reserved未知字段选项option 通…

企业国际大数据传输必须了解的5种跨国快速传输大文件工具

信息技术的迅速发展&#xff0c;带来了数据量的持续增长&#xff0c;从而日益增加了对大文件传输的需求。特别是在跨国传输大数据时&#xff0c;网络拥堵和地理限制等问题也逐渐浮现。为了解决这一难题&#xff0c;人们开始寻找更为高效、迅捷和安全的方法来进行跨国大文件传输…

Electron之初体验

Electron是一款使用Html、Css、JS开发跨平台桌面应用的框架。 话不多说直接开搞。 必坑指南&#xff1a; node版本>18.0使用淘宝镜像安装npm相关包&#xff1b;把下面两行配置放到你的npmrc文件中electron_mirrorhttps://npm.taobao.org/mirrors/electron/ ELECTRON_MIRRO…

C++STL之string类

​ 食用指南&#xff1a;本文在有C基础的情况下食用更佳 &#x1f340;本文前置知识&#xff1a;C基础 ♈️今日夜电波&#xff1a;喜劇—星野源 1:06 ━━━━━━️&#x1f49f;──────── 3:51 …

5G手机终端省电方案

5G终端带宽大、频率高&#xff0c;天线一般为4接收2发射&#xff0c;因此功耗比较高。 5G Power Saving技术为3GPP的一大主要课题&#xff0c;本文介绍几种5G省电技术。 CDRX&#xff08;Connected Discontinuous reception&#xff09;是让终端定期休眠不监听PDCCH。 WUS&a…

C语言学习系列-->看淡指针(3)

文章目录 一、字符指针变量二、数组指针变量2.1 概述2.2 数组指针初始化 三、二维数组传参本质四、函数指针五、typedef关键字六、函数指针数组 一、字符指针变量 在指针的类型中我们知道有⼀种指针类型为字符指针 char* 一般使用&#xff1a; #include<stdio.h>int main…

【COMP282 LEC6 LEC7 LEC8】

LEC 6 Example container: Map Things are stored in ascending order (based on <) by default on the first component (the string) Map access 让一个键名为“one”的值为1 添加一个键值对&#xff0c;键名是“two”&#xff0c;值为2 functor 功能原件 LEC 7

2023企业Hyper-V备份解决方案!

虚拟技术已成为IT基础设施的核心元素&#xff0c;企业长期依赖虚拟机&#xff08;VM&#xff09;为应用程序提供工作负载。Hyper-V是一款广受欢迎的虚拟化平台&#xff0c;多年来已日臻完善&#xff0c;并在各类规模的公司中得到广泛应用。 随着虚拟机使用的普及&…

【0基础入门Python Web笔记】三、python 之函数以及常用内置函数

三、python 之函数以及常用内置函数 函数函数定义函数调用函数参数返回值 常用内置函数input()函数range()函数其它 更多实战项目可进入下方官网 函数 函数是一种用于封装可重复使用代码块的工具&#xff0c;能够将一系列操作组织成一个逻辑单元。 函数定义 在Python中&…

Linux_11_系统启动和内核管理

目录 1 C entOS 6 的启动管理1.1 Linux 组成1.2 内核设计流派1.3 CentOS 6启动流程1.3.1 CentOs 6 启动流程1.3.1 硬件启动POST1.3.2 bootloader 启动/引导加载器1.3.2.1 grub 功能和组成1.3.2.2 CentOS 6 grub 安装1.3.2.3 grub legacy 管理 1.3.3 加载 kernel1.3.4 init 初始…

循环购模式:打破传统消费模式,让每一次购物成为可持续性的循环

品牌做私域运营&#xff0c;只会不断促销是没有用的&#xff0c;反而会让用户渐渐无感。更高级的私域运营玩法应该是通过场景策略来做私域&#xff0c;直击用户的痛点&#xff0c;让用户自我说服&#xff0c;提高转化率。 循环购消费模式是一种创新的商业模式&#xff0c;它能…

PostgreSQL-研究学习-介绍与安装

PostgreSQL-预研 是个很厉害的数据库的样子 ψ(*&#xff40;ー)ψ 官方文档&#xff1a;http://www.postgres.cn/docs/12/ 总的结论和备注 PgSQL 支持对JSON的支持很强大&#xff0c;以及提供了很多数学几何相关的数据类型【例&#xff1a;点&#xff0c;线条&#xff0c;几何…

[PyTorch][chapter 51][Auto-Encoder -1]

目录&#xff1a; 简介 损失函数 自动编码器的类型 一 AutoEncoder 简介&#xff1a; 自动编码器是一种神经网络&#xff0c;用于无监督学习任务.(没有标签或标记数据), 例如降维,特征提取和数据压缩. 主要任务&#xff1a; 1&#xff1a; 输入数据 …

怎样做好日志分析?

首先我们要知道日志分析是指检查并理解计算机生成的日志消息&#xff0c;例如日志事件或审计来跟踪记录&#xff0c;通过日志分析可以帮助您诊断和解决计算机系统中的问题&#xff0c;以及监视系统性能和安全性。 如果您想知道您的网络中发生了什么&#xff0c;以便洞察潜在的…

线性代数的学习和整理10:各种特殊类型的矩阵(草稿-----未完成 建设ing)

非特殊矩阵 矩阵的类型 第2大类 图形化分类 8 对角线矩阵 三角矩阵 上三角矩阵 对称矩阵 零矩阵 梯形矩阵 下面的分类&#xff0c;功能性分类 增广矩阵 伴随矩阵 正交矩阵

17.1.2 【Linux】systemd使用的unit分类

systemd 有什么好处&#xff1f; 平行处理所有服务&#xff0c;加速开机流程&#xff1a; 旧的 init 启动脚本是“一项一项任务依序启动”的模式&#xff0c;因此不相依的服务也是得要一个一个的等待。但目前我们的硬件主机系统与操作系统几乎都支持多核心架构了&#xff0c;s…

OpenGL —— 2.1、绘制第一个三角形(附源码,glfw+glad)

源码效果 C源码 vertexShader.glsl #version 330 corelayout(location 0) in vec3 aPos; void main() {gl_Position vec4(aPos.x, aPos.y, aPos.z, 1.0); };fragmentShader.glsl #version 330 coreout vec4 FragColor; void main() {FragColor vec4(1.0f, 1.0f, 1.0f, 1.0…

基于transformer预测双色球(代码+数据+一键可运行)

对AI炒股感兴趣的小伙伴可加WX群&#xff1a; 1、引言 在这期内容中&#xff0c;我们将暂时将股票搁置一旁&#xff0c;转而探索人工智能技术如何应用于另一个有趣的领域&#xff1a;预测未来双色球号码。 2、AI与双色球预测的关系 在彩票预测中&#xff0c;AI充当着数据分析…