小程序 懒加载功能实现

参考方案一:

主要是来自知友提供的代码思路

原文链接:https://zhuanlan.zhihu.com/p/162904380

他的实现思路是:在页面可以使用onPageScroll来监听滚动条的位置

缺点:组件中是无法使用的 另外 页面中使用了overflow发现无法监听滚动条的位置

我使用了该思路 并加入了从后端请求数据的步骤 供大家参考

index.js

const utils = require('../utils/utils')
const app = getApp()

Page({
  data: {
    first:[
      {
        Id: 1,
        Number: 'BN23656326561',
        CreateTime: '2021/04/21 08:12:56',
        RegionName: 'XXXXX',
        Address: '一号研发楼'
      },
      {
        Id: 2,
        Number: 'BN23656326562',
        CreateTime: '2021/04/21 08:12:56',
        RegionName: 'XXXXX',
        Address: '一号研发楼'
      },
      {
        Id: 3,
        Number: 'BN23656326563',
        CreateTime: '2021/04/21 08:12:56',
        RegionName: 'XXXXX',
        Address: '一号研发楼'
      },
      {
        Id: 4,
        Number: 'BN23656326564',
        CreateTime: '2021/04/21 08:12:56',
        RegionName: 'XXXXX',
        Address: '一号研发楼'
      },
      {
        Id: 5,
        Number: 'BN23656326565',
        CreateTime: '2021/04/21 08:12:56',
        RegionName: 'XXXXX',
        Address: '一号研发楼'
      },
      {
        Id: 6,
        Number: 'BN23656326566',
        CreateTime: '2021/04/21 08:12:56',
        RegionName: 'XXXXX',
        Address: '一号研发楼'
      },
      {
        Id: 7,
        Number: 'BN23656326567',
        CreateTime: '2021/04/21 08:12:56',
        RegionName: 'XXXXX',
        Address: '一号研发楼'
      },
      {
        Id: 8,
        Number: 'BN23656326568',
        CreateTime: '2021/04/21 08:12:56',
        RegionName: 'XXXXX',
        Address: '一号研发楼'
      },
      {
        Id: 9,
        Number: 'BN23656326569',
        CreateTime: '2021/04/21 08:12:56',
        RegionName: 'XXXXX',
        Address: '一号研发楼'
      },
      {
        Id: 10,
        Number: 'BN23656326510',
        CreateTime: '2021/04/21 08:12:56',
        RegionName: 'XXXXX',
        Address: '一号研发楼'
      },
    ],
    second:[
      {
        Id: 11,
        Number: 'BN23656326565',
        CreateTime: '2021/04/21 08:12:56',
        RegionName: 'XXXXX',
        Address: '一号研发楼'
      },
      {
        Id: 12,
        Number: 'BN23656326566',
        CreateTime: '2021/04/21 08:12:56',
        RegionName: 'XXXXX',
        Address: '一号研发楼'
      },
      {
        Id: 13,
        Number: 'BN23656326565',
        CreateTime: '2021/04/21 08:12:56',
        RegionName: 'XXXXX',
        Address: '一号研发楼'
      },
      {
        Id: 14,
        Number: 'BN23656326566',
        CreateTime: '2021/04/21 08:12:56',
        RegionName: 'XXXXX',
        Address: '一号研发楼'
      },
      {
        Id: 15,
        Number: 'BN23656326565',
        CreateTime: '2021/04/21 08:12:56',
        RegionName: 'XXXXX',
        Address: '一号研发楼'
      },
      {
        Id: 16,
        Number: 'BN23656326566',
        CreateTime: '2021/04/21 08:12:56',
        RegionName: 'XXXXX',
        Address: '一号研发楼'
      },
      {
        Id: 17,
        Number: 'BN23656326565',
        CreateTime: '2021/04/21 08:12:56',
        RegionName: 'XXXXX',
        Address: '一号研发楼'
      },
      {
        Id: 18,
        Number: 'BN23656326566',
        CreateTime: '2021/04/21 08:12:56',
        RegionName: 'XXXXX',
        Address: '一号研发楼'
      },
      {
        Id: 19,
        Number: 'BN23656326565',
        CreateTime: '2021/04/21 08:12:56',
        RegionName: 'XXXXX',
        Address: '一号研发楼'
      },
      {
        Id: 20,
        Number: 'BN23656326566',
        CreateTime: '2021/04/21 08:12:56',
        RegionName: 'XXXXX',
        Address: '一号研发楼'
      },
    ],
    pagenum: 1,
    pagesize: 10,
    total: 12,
    loading: true,
    finishedLoading: false,
    windowHeight:'',
    pageScroll: false
  },
  onLoad: function(option){
    // console.log("onLoad")
    let that = this
    wx.getSystemInfo({
      success: function(res){
        that.setData({
          windowHeight: res.windowHeight
        })
      }
    })
  },
  // 调用滚动条获取位置信息
  onPageScroll: function(e){
    // console.log(e)
    if(e&&this.data.pageScroll == false){
      this.setData({
        pageScroll: true
      })
    }
    let that = this
    if(that.data.detail[that.data.detail.length - 1].hide){
      return false
    }
    wx.getSystemInfo({
      success: function(res){
        that.setData({
          windowHeight: res.windowHeight + e.scrollTop
        })
      }
    })
    // console.log(this.data.windowHeight,e.scrollTop)
    var start = (that.data.pagenum - 1) * that.data.pagesize
    for(let i = start; i < that.data.detail.length; i++){
      if(that.data.detail[i].height <= that.data.windowHeight){
        that.data.detail[i].hide = true
      }else{
        that.data.detail[i].hide =  false
      }
    }
    that.setData({
      detail: that.data.detail
    })
    if(that.data.detail[that.data.detail.length-1].hide){
      if(that.data.detail.length<that.data.total){
        that.setData({
          pagenum: that.data.pagenum+1,
          loading: true
        })
        // 再次获取新的值
        var data = that.initial()
      }else{
        that.setData({
          finishedLoading: true
        })
      }
    }
  },
  onShow() {
    // console.log("onShow")
    // 等待 获取从后端传过来的值
    var data = this.initial()
  },
  async initial(){
    this.setData({
      pageScroll: false
    })
    const params = {
      PageNum: this.data.pagenum,
      PageSize: this.data.pagesize
    }
    await this.realIni(params)
  },
  getData(val){
    var that = this
    if(val.PageNum == 1){
      let list = that.data.first
      return new Promise((resolve, reject) => {
        setTimeout(() => {
          that.setData({
            detail: that.data.first,
            loading: false
          })
          resolve(list)
        }, 2000)
      })
    }else{
      var list = utils.deepCloneArr(that.data.detail)//深拷贝副本
      list.push(...that.data.second)
      return new Promise((resolve, reject) => {
        setTimeout(() => {
          that.setData({
            loading: false,
            detail: list
          })
          resolve(list)
        }, 3000)
      })
    }
  },
  async realIni(val) {
    const result = await this.getData(val)
    var that = this
    if(that.data.loading==false){
      var start = (that.data.pagenum - 1) * that.data.pagesize
      for(let i = start;i < result.length;i++){
        // console.log('#curr'+ i)
        wx.createSelectorQuery().select('#curr'+ i).boundingClientRect(function(rect){
          // console.log(rect,rect.top)
          result[i].height = rect.top
          // console.log(result[i].height , that.data.windowHeight)
          if(result[i].height <= that.data.windowHeight){
            result[i].hide = true
          }else{
            result[i].hide = false
          }
          if(i==(result.length -1)){
            that.setData({
              detail: result
            })
          }
        }).exec()
      }
    }
  }
})

其中utils.js里面的深拷贝函数

// 对象深拷贝函数
const deepCloneArr = function(initalArr) {
  var list = [];
  list = JSON.parse(JSON.stringify(initalArr));
  return list;
}

// 将深拷贝函数暴露出去
module.exports = {
  deepCloneArr
}

index.json

{
  "usingComponents": {
    "mp-loading": "weui-miniprogram/loading/loading"
  }
}

index.wxml 

<view class="work {{pageScroll ? 'work-long': 'work-v'}}">
  <view class="work-header">
    <text>固定</text>
  </view>
  <view class="work-header-t">
  </view>

  <view class="lazyload">
    <view wx:for="{{detail}}" wx:key="index" class="undeal-item {{item.hide?'animation':''}}" id="curr{{index}}">
      <view wx:if="{{item.hide}}">
        <view class="undeal-item-info">
            <view class="undeal-item-info-oneline">
              <view class="undeal-item-info-left">
                <view class="undeal-item-info-left-label">编号</view>
                <view class="undeal-item-info-left-value">{{item.Number}}</view>
              </view>
              <view class="undeal-item-info-right">
                <text class="undeal-item-info-right-label">创建时间</text>
                <text class="undeal-item-info-right-value">{{item.CreateTime}}</text>
              </view>
            </view>
            <view class="undeal-item-info-twoline">
              <view class="undeal-item-info-left">
                <text class="undeal-item-info-left-label item-label-style">所属区域</text>
                <text class="undeal-item-info-left-value item-style">{{item.RegionName}}</text>
              </view>
              <view class="undeal-item-info-left">
                <text class="undeal-item-info-left-label item-label-style">目的地</text>
                <text class="undeal-item-info-left-value item-style">{{item.Address}}</text>
              </view>
            </view> 
        </view>
      </view> 
    </view>

    <mp-loading wx:if="{{!finishedLoading}}" class="loading-style" type="dot-gray" show="{{loading}}"></mp-loading>
    <text wx:else class="loading-txt">已经到底了...</text>
  
  </view>

</view>

index.css

.work{
  width: 100vw;
  height: auto;
  position: relative;
  background-color: #F2F2F2;
}

.work-v{
  height: 100vh;
}

.work-long{
  height: 100%;
}


.work-header{
  position: fixed;
  /* position: sticky ;  */
  top: 0;
  width: 100%;
  height: 120rpx;
  z-index: 1000;
  float: left;
  /* top: 0rpx; */
  left: 0;
  background-color: red;
  padding: 19rpx 40rpx 4rpx 40rpx;
}

.work-header-t{
  width: 100%;
  height: 120rpx;
}

.lazyload{
  width: 100%;
  height: 100%;
  background-color: pink;
  /* 失效 */
  /* height: calc(100vh - 120rpx); */
  /* overflow-y: scroll; */
  padding-bottom: calc(env(safe-area-inset-bottom) / 2);
}

.center{
  width: 100%;
  margin: 30rpx 10% 0;
  float: left;
  font-size: 26rpx;
  height: 200rpx;
  background-color: #fff;
}

.animation{
  animation: center 1s;
}

@keyframes center{
  from{
    transform: scale(0.5);
  }
  to{
    transform: scale(1);
  }
}

/* 基本信息 */
.undeal-item{
  height: 240rpx;
  margin-top: 10rpx;
  background-color: #fff;
}

.undeal-item-info{
  padding: 0 26rpx 0rpx 38rpx;
  display: flex;
  flex-direction: column;
}

.undeal-item-info-oneline,
.undeal-item-info-twoline{
  margin-top: 16rpx ;
  font-size: 22rpx;
  display: flex;
  justify-content: space-between;
}

.undeal-item-info-oneline{
  color: #237AE4;
}

.undeal-item-info-left{
  flex: 1;
  display: flex;
}

.undeal-item-info-right{
  flex: 1;
  display: flex;
}

.undeal-item-info-left-label{
  width: 110rpx;
}

.undeal-item-info-right-label{
  width: 120rpx;
}

.undeal-item-info-left-value,
.undeal-item-info-right-value{
  justify-content: flex-end;
}

.item-label-style{
  color: #666;
}

.item-style{
  color: #333;
}

/* loading样式 */
.loading-style{
  display: block;
  padding-top: 40rpx;
  padding-bottom: 40rpx;
}

.loading-txt{
  font-size: 20rpx;
  padding-bottom: 10rpx;
  text-align: center;
  display: flex;
  align-items: center;
  justify-content: center;
  color: #666;
  background-color: lightgray;
}

对于上述方案有固定的头部区域,滚动条还是可以穿过,观感很不好

因此,带来第二种方案

参考方案二:

主要实现思路是:在需要懒加载的区域引入微信官方文档中的scroll-view组件

参考链接:https://developers.weixin.qq.com/miniprogram/dev/component/scroll-view.html

lazyr.js

const utils = require('../../utils/utils')
const app = getApp()

Component({
  /**
   * 组件的属性列表
   */
  properties: {

  },

  /**
   * 组件的初始数据
   */
  data: {
    first:[
      {
        Id: 1,
        Number: 'BN23656326561',
        CreateTime: '2021/04/21 08:12:56',
        RegionName: 'XXXXX',
        Address: '一号研发楼'
      },
      {
        Id: 2,
        Number: 'BN23656326562',
        CreateTime: '2021/04/21 08:12:56',
        RegionName: 'XXXXX',
        Address: '一号研发楼'
      },
      {
        Id: 3,
        Number: 'BN23656326563',
        CreateTime: '2021/04/21 08:12:56',
        RegionName: 'XXXXX',
        Address: '一号研发楼'
      },
      {
        Id: 4,
        Number: 'BN23656326564',
        CreateTime: '2021/04/21 08:12:56',
        RegionName: 'XXXXX',
        Address: '一号研发楼'
      },
      {
        Id: 5,
        Number: 'BN23656326565',
        CreateTime: '2021/04/21 08:12:56',
        RegionName: 'XXXXX',
        Address: '一号研发楼'
      },
      {
        Id: 6,
        Number: 'BN23656326566',
        CreateTime: '2021/04/21 08:12:56',
        RegionName: 'XXXXX',
        Address: '一号研发楼'
      },
      {
        Id: 7,
        Number: 'BN23656326567',
        CreateTime: '2021/04/21 08:12:56',
        RegionName: 'XXXXX',
        Address: '一号研发楼'
      },
      {
        Id: 8,
        Number: 'BN23656326568',
        CreateTime: '2021/04/21 08:12:56',
        RegionName: 'XXXXX',
        Address: '一号研发楼'
      },
      {
        Id: 9,
        Number: 'BN23656326569',
        CreateTime: '2021/04/21 08:12:56',
        RegionName: 'XXXXX',
        Address: '一号研发楼'
      },
      {
        Id: 10,
        Number: 'BN23656326510',
        CreateTime: '2021/04/21 08:12:56',
        RegionName: 'XXXXX',
        Address: '一号研发楼'
      },
    ],
    second:[
      {
        Id: 11,
        Number: 'BN23656326565',
        CreateTime: '2021/04/21 08:12:56',
        RegionName: 'XXXXX',
        Address: '一号研发楼'
      },
      {
        Id: 12,
        Number: 'BN23656326566',
        CreateTime: '2021/04/21 08:12:56',
        RegionName: 'XXXXX',
        Address: '一号研发楼'
      },
      {
        Id: 13,
        Number: 'BN23656326565',
        CreateTime: '2021/04/21 08:12:56',
        RegionName: 'XXXXX',
        Address: '一号研发楼'
      },
      {
        Id: 14,
        Number: 'BN23656326566',
        CreateTime: '2021/04/21 08:12:56',
        RegionName: 'XXXXX',
        Address: '一号研发楼'
      },
      {
        Id: 15,
        Number: 'BN23656326565',
        CreateTime: '2021/04/21 08:12:56',
        RegionName: 'XXXXX',
        Address: '一号研发楼'
      },
      {
        Id: 16,
        Number: 'BN23656326566',
        CreateTime: '2021/04/21 08:12:56',
        RegionName: 'XXXXX',
        Address: '一号研发楼'
      },
      {
        Id: 17,
        Number: 'BN23656326565',
        CreateTime: '2021/04/21 08:12:56',
        RegionName: 'XXXXX',
        Address: '一号研发楼'
      },
      {
        Id: 18,
        Number: 'BN23656326566',
        CreateTime: '2021/04/21 08:12:56',
        RegionName: 'XXXXX',
        Address: '一号研发楼'
      },
      {
        Id: 19,
        Number: 'BN23656326565',
        CreateTime: '2021/04/21 08:12:56',
        RegionName: 'XXXXX',
        Address: '一号研发楼'
      },
      {
        Id: 20,
        Number: 'BN23656326566',
        CreateTime: '2021/04/21 08:12:56',
        RegionName: 'XXXXX',
        Address: '一号研发楼'
      },
    ],
    query:'',
    pagenum: 1,
    pagesize: 10,
    total: 20,
    loading: true,
    finishedLoading: false,
    recycleList: [],
    // 查询的触发标志
    flag: '',
    windowHeight: '',
    areaInfo: {},
    currentStatus: 0,
    pageScroll: false

  },
  lifetimes: {
    attached: function () {
      
      this.setData({
        pagenum: 1,
        recycleList: [],
        loading: true,
        finishedLoading: false
      })
      var that = this
      wx.getSystemInfo({
        success: function(res){
          that.setData({
            windowHeight: res.windowHeight
          })
        }
      })
   
    },
    ready: function(){
      console.log("ready")
      var inidetail = this.initial()
    },
    moved: function () { 

    },
    detached: function () { 

    },
  },

  /* 组件的方法列表 */
  methods: {
    async initial(){
      const params = {
        PageNum: this.data.pagenum,
        PageSize: this.data.pagesize
      }
      await this.realIni(params)
    },
    getData(val){
      var that = this
      if(val.PageNum == 1){
        let list = that.data.first
        return new Promise((resolve, reject) => {
          setTimeout(() => {
            that.setData({
              loading: false,
              recycleList: that.data.first
            })
            
            resolve(that.data.recycleList)
          }, 2000)
        })
      }else{
        // var list = utils.deepCloneArr(that.data.detail)//深拷贝副本
        // list.push(...that.data.second)
        return new Promise((resolve, reject) => {
          setTimeout(() => {
            let list =  utils.deepCloneArr(that.data.recycleList)
            list.push(...that.data.second)
            that.setData({
              loading: false,
              recycleList: list
            })
            resolve(list)
          }, 3000)
        })
      }
    },
    async realIni(val) {
      const result = await this.getData(val)
      console.log(result)
    },
    getScroll:function(e){
      let that = this
      if(that.data.recycleList.length<that.data.total){
        that.setData({
          pagenum: that.data.pagenum+1,
          loading: true
        })
        // 再次获取新的值
        var data = that.initial()
      }else{
        if(!that.data.finishedLoading){
          that.setData({
            finishedLoading: true
          })
        }
      }
    },
  }
})

lazyr.json

{
  "component": true,
  "usingComponents": {
    "mp-loading": "weui-miniprogram/loading/loading"
  }
}

lazyr.wxml

<view class="work">
  <view class="work-header-f">
    <view class="work-header">
      <text>固定</text>
    </view>
    <view class="work-header-t">
    </view>
  </view>

  <view wx:if="{{ total > 0}}">
    <scroll-view scroll-y="true" style='height:calc(100vh - 130rpx)' 
      class="{{ total>pagesize? '' : 'lazyload'}}"
      bindscrolltolower="getScroll">
      <view wx:for="{{recycleList}}" wx:key="index" class="undeal-item list_item_box" id="undeal{{id}}">
        <view class="undeal-item-info">
          <view class="undeal-item-info-oneline">
            <view class="undeal-item-info-left">
              <view class="undeal-item-info-left-label">编号</view>
              <view class="undeal-item-info-left-value">{{item.Number}}</view>
            </view>
            <view class="undeal-item-info-right">
              <text class="undeal-item-info-right-label">创建时间</text>
              <text class="undeal-item-info-right-value">{{item.CreateTime}}</text>
            </view>
          </view>
          <view class="undeal-item-info-twoline">
            <view class="undeal-item-info-left">
              <text class="undeal-item-info-left-label item-label-style">所属区域</text>
              <text class="undeal-item-info-left-value item-style">{{item.RegionName}}</text>
            </view>
            <view class="undeal-item-info-left">
              <text class="undeal-item-info-left-label item-label-style">目的地</text>
              <text class="undeal-item-info-left-value item-style">{{item.Address}}</text>
            </view>
          </view> 
        </view>
      </view>
      <mp-loading wx:if="{{!finishedLoading}}" class="loading-style" type="dot-gray" show="{{loading}}"></mp-loading>
      <text wx:else class="loading-txt">已经到底了...</text>
    </scroll-view>
  </view>

  <view wx:else class="nodatab {{currentStatus == 0? '': 'lazyload-p'}}">
    <text>暂无内容</text>
  </view>

</view>

lazyr.wxss

.work{
  margin-top: 0rpx;
  height: 100vh;
  background-color: lightgray;
}

.work-header{
  width: 100%;
  height: 120rpx;
  position: fixed;
  z-index: 1000;
  float: left;
  top: 0rpx;
  left: 0;
  background-color: red;
  padding: 19rpx 40rpx 4rpx 40rpx;
}

.work-header-t{
  width: 100%;
  height: 120rpx;
}

.lazyload{
  height: 100% !important;
  width: 100%;
  padding-bottom: calc(env(safe-area-inset-bottom) / 2);
}

/* 基本信息 */
.undeal-item{
  width: 100%;
  height: 240rpx;
  margin-top: 10rpx;
  background-color: #fff;
}

.undeal-item-info{
  padding: 0 26rpx 0rpx 38rpx;
  display: flex;
  flex-direction: column;
}

.undeal-item-info-oneline,
.undeal-item-info-twoline{
  margin-top: 16rpx ;
  font-size: 22rpx;
  display: flex;
  justify-content: space-between;
}

.undeal-item-info-oneline{
  color: #237AE4;
}

.undeal-item-info-left{
  flex: 1;
  display: flex;
}

.undeal-item-info-right{
  flex: 1;
  display: flex;
}

.undeal-item-info-left-label{
  width: 110rpx;
}

.undeal-item-info-right-label{
  width: 120rpx;
}

.undeal-item-info-left-value,
.undeal-item-info-right-value{
  justify-content: flex-end;
}

.item-label-style{
  color: #666;
}

.item-style{
  color: #333;
}

/* loading样式 */
.loading-style{
  display: block;
  padding-top: 40rpx;
  padding-bottom: 40rpx;
}

.loading-txt{
  font-size: 20rpx;
  padding-bottom: 10rpx;
  text-align: center;
  display: flex;
  align-items: center;
  justify-content: center;
  color: #666;
  background-color: lightgray;
}

数据接口:https://api.getweapp.com/vendor/lightstao/searchkeyhttps://api.getweapp.com/vendor/lightstao/product/search微信小程序中,懒加载特效让人头疼不已,因为小程序完全没法操作dom,所以位置的操作在小程序中,变得极其的难~~先看特效:我们将其拆分为如下几个步骤进行讲解~~1)如何获取图片的位置高度先看一张图:通过上图可以知道,图片位置高度其实可以通过img.height margin值算出。js代码:arrHight[i] = Math.floor(i/2)*(img.height   margin-bottom);为何是Math.floor(i/2)呢,因为同一排两张图片高度一样,比如i=0和i=1,通过Math.floor得出值都为0,所以可以保证同一排的两张图片位置高度是同一个值。2)替换默认图片先看效果图片:wxml代码:<image src="{{arr[index] ? productArr[index].Image : 'default.jpg'}}"></image>思路很明显,一开始arr[index]中都是false,所以默认都是default图片但是随着往下移动,有些arr[index]的值变为true,所以替换默认图片js代码:for (var i = 0; i < this.data.productArr.length; i ) {   if (arrHight[i] < scrollTop) {       if (arr[i] == false) {           arr[i] = true;       }   } }思路相当清晰,无需多言~~3)懒加载中渐显特效先看效果:wxss代码:.product_image{   opacity: 0;   width: 100%;   height: 70%;   transition: opacity 1s linear 2s; } .loaded{     opacity: 1; }其实就是opacity的一个过渡动画而已,so easy~~作者:小小小是我
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值