微信小程序Skyline模式下瀑布长列表优化成虚拟列表,解决内存问题

微信小程序长列表,渲染的越多就会导致内存吃的越多。特别是长列表的图片组件和广告组件。

为了解决内存问题,所以看了很多人的资料,都不太符合通用的解决方式,很多需要固定子组件高度,但是瀑布流是无法固定的,所以需要找更好的方式。好在有一篇可以借鉴的文章在其基础上做了修改,解决了内存问题!

借鉴了以下文章的解决方式,由于借鉴章依旧存在内存泄漏问题,所以本文章改进后不再内存泄漏

借鉴文链接:解决小程序渲染复杂长列表,内存不足问题 - 掘金 (juejin.cn)

进入下面小程序可以体验效果

代码效果图

老规矩,直接上代码,各位直接引用!

一、定义骨架组件

WXML:

html 复制代码
<view class="list-item" id="list-item-{{skeletonId}}" style="min-height: {{height}}px;">
    <block wx:if="{{showSlot}}">
        <view style="height: 1px; z-index: 1;">{{parentIndex}},{{index}}</view>
        <image style="width: 100%;height: 100%;" mode="aspectFill" src="https://img-blog.csdnimg.cn/direct/25e4d10c5187409d9190a2f47297503e.jpeg"></image>
    </block>
</view>
<!-- 广告,不用可以直接去掉 -->
<block wx:if="{{(index+1)%12==0}}">
    <view class="adbk" style="min-height: {{(shkey==='list'||shkey==='tx')?'330px':'315px'}};background:#ffff">
        <block wx:if="{{showSlot}}">
            <ad-custom 
            class="girdAd" 
            unit-id="adunit-xxxxx"></ad-custom>
        </block>
    </view>
</block>

JS:

javascript 复制代码
// components/skeleton.js
let app = getApp() 
Component({
  lifetimes:{
    created(){
        //设置一个走setData的数据池
        this.extData = {
          listItemContainer: null,
        }
    },
    attached(){
        
    },
    detached() {
      try {
        this.extData.listItemContainer.disconnect()
      } catch (error) {
  
      }
      this.extData = null
    },
  
    ready() {
      this.setData({
        skeletonId: this.randomString(8), //设置唯一标识
        color:this.randomColor()
      })
      wx.nextTick(() => {
        // 修改了监听是否显示内容的方法,改为前后showNum屏高度渲染
        // 监听进入屏幕的范围relativeToViewport({top: xxx, bottom: xxx})
        let { windowHeight = 667 } = wx.getSystemInfoSync() //请自行优化这个取值
        let showNum = 2 //超过屏幕的数量,目前这个设置是上下2屏
        try {
          this.extData.listItemContainer = this.createIntersectionObserver()
          this.extData.listItemContainer.relativeToViewport({ top: showNum * windowHeight, bottom: showNum * windowHeight })
            .observe(`#list-item-${this.data.skeletonId}`, (res) => {
              let { intersectionRatio } = res
              if (intersectionRatio === 0) {
                // console.log('【卸载】', this.data.skeletonId, '超过预定范围,从页面卸载')
                this.setData({
                  showSlot: false
                })
              } else {
                // console.log('【进入】', this.data.skeletonId, '达到预定范围,渲染进页面')
                this.setData({
                  showSlot: true,
                  height: res.boundingClientRect.height
                })
              }
            })
        } catch (error) {
          console.log(error)
        }
      })
      
    }
  },
  /**
   * 组件的属性列表
   */
  properties: {
    parentIndex:{
       type:Number,
       value:0
    },
    index:{
      type:Number,
      value:0
    }
  },
  /**
   * 组件的初始数据
   */
  data: {
    height: 0, //卡片高度,用来做外部懒加载的占位
    showSlot: true, //控制是否显示当前的slot内容
    skeletonId: '',
    color:'#7179b1',
    colorList:[
      '#7179b1',
      '#d66f33',
      '#33d665',
      '#cc33d6',
      '#7233d6',
      '#338bd6',
      '#b5d2ea',
      '#6f0c0c',
      '#d43f8b',
      '#00ccec',
      '#2e666f',
      '#ffcd18'
    ]
  },

  /**
   * 组件的方法列表
   */
  methods: {
    /**
     * 生成随机的字符串
     */
    randomString(len) {
      len = len || 32;
      var $chars = 'abcdefhijkmnprstwxyz2345678'; /****默认去掉了容易混淆的字符oOLl,9gq,Vv,Uu,I1****/
      var maxPos = $chars.length;
      var pwd = '';
      for (var i = 0; i < len; i++) {
        pwd += $chars.charAt(Math.floor(Math.random() * maxPos));
      }
      return pwd;
    },
    randomColor(){
        let num = Math.ceil(Math.random()*10);
        return this.data.colorList[num];
    }
  }
})

WXSS:

css 复制代码
.girdAd{
  border-radius: 10px;
  z-index: 11;
}
.adbk{
  background: #636363;
  border: 1px solid #f3f3f3;
  border-radius: 10px;
  margin-top: 10px;
}

.adloading{
   line-height: 300px;
   color: rgb(255, 255, 255);
   text-align: center;
   position: absolute;
   right: 23%;
}

二、业务代码使用骨架组件

业务代码中,就是数组的数据需要频繁的使用setData这个接口,所以需要避免频繁操作。

将list 数据改成二位数组。

json需要引入: "skeleton":"/components/skeleton/skeleton"

WXML:

html 复制代码
<scroll-view 
   style="height: 100vh;"
  type="custom"
  scroll-y="{{true}}" 
  lower-threshold="{{100}}"
  scroll-top="0"
  scroll-with-animation="{{true}}" 
  bindscrolltolower="loadmore">
  <grid-view type="masonry" cross-axis-count="{{2}}" cross-axis-gap="{{10}}" main-axis-gap="{{10}}" padding="{{[5,5,0,5]}}">
    <block wx:for-item="parentItem" wx:for-index="parentIndex" wx:for="{{list}}" wx:key="{{parentIndex}}">
      <!-- 这个view仅作为间隔区分展示用,并不是必须的 -->
      <block wx:if="{{parentIndex!=0}}"
        wx:for="{{parentItem}}" 
        wx:key="{{index}}" >
        <!-- 使用 -->
        <skeleton parentIndex="{{parentIndex}}" index="{{index}}"></skeleton>
      </block>
    </block>
  </grid-view>
</scroll-view>

JS:

javascript 复制代码
Component({
  lifetimes:{
     created(){
        this.loadmore()
     }
  },
  data: {
    list: [[{}]]
  },
  methods: {
    loadmore: function() {
      //过长的list需要做二维数组,因为setData一次只能设置1024kb的数据量,如果过大的时候,就会报错
      //二维数组每次只设置其中一维,所以没有这个问题
      let nowList = `list[${this.data.list.length}]`
      let demoList = this.getList(100)
      this.setData({
        [nowList]: demoList
      })
    },
    /**
     * 每次吸入num条数据
     */
    getList(num) {
      let list = []
      for (let i = 0; i < num; i++) {
        list.push({
          height: this.getRadomHeight()
        })
      }
      return list    
    },
    /**
     * 生成随机(100, 400)高度
     */
    getRadomHeight() {
      return parseInt(Math.random()*100 + 300)
    }
  },
})
相关推荐
qq_332783541 小时前
wx小程序turf.js判断点是否位于该多边形内部
小程序
放逐者-保持本心,方可放逐2 小时前
微信小程序=》基础=》常见问题=》性能总结
前端·微信小程序·小程序·前端框架
计算机-秋大田2 小时前
基于微信小程序的养老院管理系统的设计与实现,LW+源码+讲解
java·spring boot·微信小程序·小程序·vue
钰@5 小时前
小程序开发者工具的network选项卡中有某域名的接口请求,但是在charles中抓不到该接口
运维·服务器·小程序
尚学教辅学习资料6 小时前
基于微信小程序的电商平台+LW示例参考
java·微信小程序·小程序·毕业设计·springboot·电商平台
尘浮生6 小时前
Java项目实战II基于微信小程序的移动学习平台的设计与实现(开发文档+数据库+源码)
java·开发语言·数据库·spring boot·学习·微信小程序·小程序
小泽呀x8 小时前
微信小程序中使用离线版阿里云矢量图标
微信小程序·小程序
fakaifa8 小时前
CRMEB Pro版v3.1源码全开源+PC端+Uniapp前端+搭建教程
前端·小程序·uni-app·php·源码下载
托马斯-酷涛9 小时前
小程序源码-模版 100多套小程序(附源码)
小程序
小蒜学长11 小时前
springboot基于SpringBoot的企业客户管理系统的设计与实现
java·spring boot·后端·spring·小程序·旅游