zoukankan      html  css  js  c++  java
  • 微信小程序列表加载更多

    概述

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

    详细

    一、前言

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

    二、运行效果

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

    三、实现过程

     

    总体思路如何:

    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 {
       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;
       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 {
       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 {
       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

    四、其他补充

    暂时没有

    注:本文著作权归作者,由demo大师发表,拒绝转载,转载需要作者授权

  • 相关阅读:
    iOS开发 -------- AFNetworking使用中遇到的小问题
    iOS开发 -------- AFNetworking实现简单的断点下载
    规则引擎-BRMS在企业开发中的应用
    MySQL系列教程(四)
    MySQL系列教程(三)
    MySQL系列教程(二)
    MySQL系列教程(一)
    OWASP Top 10十大风险 – 10个最重大的Web应用风险与攻防
    【事务】<查询不到同一调用方法其它事务提交的更新>解决方案
    iOS控制反转(IoC)与依赖注入(DI)的实现
  • 原文地址:https://www.cnblogs.com/demodashi/p/9453005.html
Copyright © 2011-2022 走看看