欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  移动技术

小程序文章列表超出1024kb的解决方案兼容ios和安卓

程序员文章站 2022-06-24 12:08:15
最近开发小程序,应客户的需求,在这个小程序官方自带的深坑里摸爬滚打了很久,为的就是解决文章列表翻页加载更多数据,数据的大小超过了1024KB的解决方案。先上图,为了实现无限翻页,小程序不会因为setData数据量过大而白屏崩溃唯一要注意的是,此处的顶部导航栏是swiper组件,下方的文章列表不是swiper组件,因此无法实现点击顶部导航栏下方可以跟随滑动,因为很多平台都没有这样做,那是因为swiper-item会有超出数量的限制,就算后端返回的数据可以无限存放在setData内,也没有办法完整的显示出...

最近开发小程序,应客户的需求,在这个小程序官方自带的深坑里摸爬滚打了很久,为的就是解决文章列表翻页加载更多数据,数据的大小超过了1024KB的解决方案。
先上图,为了实现无限翻页,小程序不会因为setData数据量过大而白屏崩溃
小程序文章列表超出1024kb的解决方案兼容ios和安卓
唯一要注意的是,此处的顶部导航栏是swiper组件,下方的文章列表不是swiper组件,因此无法实现点击顶部导航栏下方可以跟随滑动,因为很多平台都没有这样做,那是因为swiper-item有超出数量的限制就算后端返回的数据可以无限存放在setData内,也没有办法完整的显示出来。这是小程序官方规定的,我也是查了很久才知道有这样一个深坑。此处的效果,仅为点击顶部导航栏,下方内容进行了替换,而非点击顶部滚动后下方的列表也跟随滚动。
不墨迹,直接上代码:

以下这段代码 是解决本问题的核心代码

/**
 * @module SafeRenderUtil
 */

/**
 * 安全渲染的工具类
 * 解决的问题:分页加载时,数组拼接起来在渲染,当数据超过 1M 后,无法再加载
 * @example
 * import SafeRenderUtil from '@xxx/lib/safeRenderUtil';
 * // 初始化
 * this.SafeRenderUtil = new SafeRenderUtil({
 *   arrName: 'arrName',
 *   formatItem: (item) => {
 *     //裁剪每一项的图片...
 *     return item;
 *   },
 *   setData: this.setData.bind(this)
 * });
 * // 将数组传递进来进行渲染
 * this.SafeRenderUtil.addList(res.data.data);
 */
class SafeRenderUtil {
  /**
   * @param {String} opts.arrName 数组名称
   * @param {Function} opts.formatItem 处理数组的每一个 item ,并将该 item 返回
   * @param {Function} opts.setData 调用页面的渲染方法
   */
  constructor(opts) {
    this.arrName = opts.arrName;
    this.formatItem = opts.formatItem;
    this.setData = opts.setData;
    this.originLen = 0; //原始数组长度
  }
  /**
   * @param {Array} arr 需要渲染的数组
   */
  addList(arr) {
    if (arr && arr.length) {
      let newList = {};
      for (let i = 0; i < arr.length; i++) {
        let item = arr[i];
        if (typeof(this.formatItem) === 'function') {
          item = this.formatItem(item);
        }
        newList[`${this.arrName}[${this.originLen}]`] = item;
        this.originLen += 1;
      };
      this.setData(newList);
    }
  }
  /**
   * 清空数组数据
   */
  clearArr() {
    this.setData({
      [`${this.arrName}`]: []
    });
    this.originLen = 0;
  }
}
module.exports = SafeRenderUtil

封装了一个可以导出的类,在其内部对后端接口返回的数据 进行了处理。
具体的做法 还需要结合接口返回的数据 进行处理:
**

1.页面对应的xml代码如下:

**

<!-- tab导航栏 -->
			<scroll-view scroll-x="true" style="position: fixed;top:{{navHeight}}px;" class="nav" scroll-left="{{navScrollLeft}}" scroll-with-animation="{{true}}">
				<block wx:for="{{navData}}" wx:for-index="idx" wx:for-item="navItem" wx:key="idx">
					<view class="nav-item {{currentTab == idx ?'active':''}}" data-current="{{idx}}" data-typeid="{{navItem.typeId}}" bindtap="switchNav">
						<text>{{navItem.typeName}}</text>
					</view>
				</block>
			</scroll-view>
			<!-- 下方文章列表 -->
					<scrollList class="scroll-view"  style="height:{{tab_content}}px;box-sizing: border-box;top: {{navHeight + 40}}px;left: 0;position: fixed;width: 100%;" pull="{{pull}}" push="{{push}}" data-index="{{idx}}" listLength="{{clueData.length}}" bindrefresh="refresh" bindgetMore="getMore">
						<view class="sede_yue">
							<view class="xtal_app" wx:if="{{arrList.length!=0}}">
								<view wx:key="id" wx:for="{{arrList}}" wx:for-item="items">
									<view class="flex-coll" bindtap="goNewsDetail" data-url="{{item.url}}" data-articleId="{{item.articleId}}" wx:key="id" wx:for="{{items}}" wx:for-item="item">
										<view class="items" wx:if="{{item.typography==3}}">
											<view class="itemTitle">
												{{item.title}}
											</view>
											<view class="itemTime"><text style="padding-right:20rpx">{{item.userName}}</text><text>{{item.updateTime}}</text></view>
										</view>
										<view class="items flex-row" wx:if="{{item.typography==1}}">
											<view class="itemLeft">
												<view class="itemTitle">
													{{item.title}}
												</view>
												<view class="itemTime">
													<text style="padding-right:20rpx">{{item.userName}}</text><text>{{item.updateTime}}</text>
												</view>
											</view>
											<view class="itemRight">
												<image src='{{item.introduceImg}}' mode='aspectFill'></image>
											</view>
										</view>
										<view wx:if="{{item.typography==2}}">
											<view class="items" style="border-bottom:none;">
												<view class="itemTitle">
													{{item.title}}
												</view>
												<view class="itemTime"><text style="padding-right:20rpx">{{item.userName}}</text><text>{{item.updateTime}}</text></view>
											</view>
											<view class="imgBox">
												<view class="imgList" wx:for="{{item.imgList}}" wx:for-item="img" wx:key="img">
													<image src='{{img}}' mode='aspectFill'></image>
												</view>
											</view>
										</view>
									</view>
								</view>
								<!-- </view> -->
							</view>
							<view class="{{arrList.length==0 ? '' : 'xtal_app'}}" style="color:#ababab;text-align:center;padding-top:360rpx;font-size:28rpx" wx:if="{{showArticle}}">
								<image src='../../images/nodata.png' style="width:242rpx;height:200rpx" mode="aspectFit"></image>
								<view style="color:#999;font-size:12px;text-align:center">当前暂无资讯~</view>
							</view>
						</view>
					</scrollList>

2.js文件调用后端接口处理返回的数据,即获取文章列表

.....
import util from '../../utils/util.js';
import SafeRenderUtil from '../../utils/safeUtils.js'
.....
 //点击获取文章列表
  getArticleList(pageNo,typeId,override){
    let arrList = []
    util.request(util.localUrl + '/applet/article/articleList?size=' + this.data.size +'&current=' +pageNo + '&typeId=' + typeId, 'POST', { 'content-type': 'application/json' }, {}).then(res => {
      console.log(res)
      if(res.code==0){
        this.setData({
          pages:res.data.pages,
          hasNextPage:res.data.hasNextPage,
          current:res.data.current
        })
        if(res.data.records.length!=0){
        //对页面上三种不同类型摘要图片字段的处理
        res.data.records.forEach(item=>{
          arrList.push(item)
          if(item.typography==2){
            let imgList = item.introduceImg.split(',')
            item.imgList = imgList;
          }
        })
      
        this.setData({
          showArticle:false,  //控制是否有更多数据的显隐
          ['articleList[' + (this.data.current-1) + ']']: res.data.records  //此处是第一次处理setData的问题 防止数据大小超出1024KB
        })
        console.log(this.data)
        console.log(this.data.articleList)
        this.SafeRenderUtil = new SafeRenderUtil({
          arrName: 'arrList',  //这里的arrList是最后输出到页面 做数据循环的arrList
          addList: (item) => {
            return item;
          },
          setData: this.setData.bind(this)
        });
        this.SafeRenderUtil.addList(this.data.articleList); //此处将之前处理过的articleList数据进行处理 并且已经赋值黑了arrList
      }else{
        this.setData({
          showArticle:true
        })
      }
      }else{
        wx.showToast({
          title: res.msg,
          icon:"none"
        })
      }
    })
  },

3.文章列表采用的是scrollList这个插件

(我屏蔽了一行scroll-view的标签,是因为之前使用bindtouchstartbindtouchend会导致页面始终存在卡顿 安卓和ios都无法兼容这个问题,页面稍微滑动就会触发翻页 调用接口,这里改成了 lower-threshold=“100” 距离底部100px 和 bindscrolltolower=“getList” 并且设置了style=“height:100%”

<scroll-view class="message scroll-view client-pool-list" scroll-y="{{true}}" lower-threshold="100" bindscrolltolower="getList" bindscrolltotop="getListTop" style="height:100%">
<!-- <scroll-view class="message scroll-view client-pool-list" scroll-y="{{true}}" lower-threshold="1" bindtouchstart="touchstart" bindtouchend="touchmove"> -->
  <view class="pull-refresh {{pull.isLoading ? 'chu' : 'jin'}}" wx:if="{{pull.isLoading}}" id="pull-refresh">
    <view class="refresh-loading"></view>
    <view class="loading_text">{{pull.pullText}}</view>
  </view>
  <slot></slot> <!-- slot接受内容 -->
  <view class="pull-refresh pisu_bum" wx:if="{{push.isLoading}}">
    <view class="refresh-loading"></view>
    <view class="loading_text">{{push.pullText}}</view>
  </view>
</scroll-view>

附scrollList插件的js代码:

Component({
  options: {
    multipleSlots: true, // 在组建定义时的选项中启用多slot支持
  },
  /**
  * 组件的属性列表
  */
  properties: {
    listLength: {
      type: Number,
      value: 0
    },
    pull: {
      type: Object,
      value: {}
    },
    push: {
      type: Object,
      value: {}
    }
  },
  /**组件所在页面的生命周期声明对象 */
  pageLifetimes: {
    show() { // 页面被展示
      this.setData({
        pull: this.properties.pull,
        push: this.properties.push,
      })
    },
  },
  /**
   * 组件的初始数据
   */
  data: {
    pull: {},
    push: {},
    slideStart: [],
    moveTime: 0,
  },
  /**自定义方法 */
  methods: {
    getList(){
    // 将getMore通过参数的形式传递给父组件
      this.triggerEvent('getMore',{ refresh: 'jiazaimore.........................................................................'})
    },
    getListTop(){
    // 将getMoreTop通过参数的形式传递给父组件
      this.triggerEvent('getMoreTop',{ refresh: 'top........................................................................'})
    },
    /**开始滑动  此处已弃用 */
    touchstart(e) {
      /**记录开始滑动的时间 */
      this.setData({
        slideStart: e.changedTouches[0]
      })
    },
    /**滑动  此处已弃用 */
    touchmove(e) {
      console.log(e)
      let moveTime = new Date().getTime(); // 当前时间
      if (moveTime - this.data.moveTime <= 2000) {
        return
      } else {
        this.setData({
          moveTime: moveTime
        })
      }
      let slideStart = this.data.slideStart;
      let slideMove = e.changedTouches[0];
      let startX = slideStart.pageX;
      let startY = slideStart.pageY;
      let moveEndX = slideMove.pageX;
      let moveEndY = slideMove.pageY;
      let X = moveEndX - startX;
      let Y = moveEndY - startY;
        // debugger
      if (Math.abs(Y) > Math.abs(X) && Y > 0) { // 从上向下滑
        console.log("top 2 bottom");
        this.pullRefresh()
      } else if (Math.abs(Y) > Math.abs(X) && Y < 0) { // 从下向上滑
        console.log("bottom 2 top");
        this.loadMore()
      }
    },
    /**下拉刷新 */
    pullRefresh(e) {
      this.triggerEvent('refresh', { refresh: true })  // 将refresh通过参数的形式传递给父组件  此处已弃用
    },
    /**上拉加载更多 */
    loadMore(e) {
      this.triggerEvent('toload', { toload: true })  // 将toload通过参数的形式传递给父组件   此处已弃用
    }
  }

4.引入这个插件 在列表页的json文件里 进行配置

代码如下:

{
  "navigationStyle": "custom",
  "backgroundColorTop": "#00a6fc",
  "disableScroll": true,
  "usingComponents": {
    "navbar": "../pages/components/navbar_lf/index",
    "scrollList": "../pages/components/scrollList/scrollList"
  }
}

5.页面的加载向下翻页 加载更多数据 也就是getMore这个方法,具体如下:

 getMore(e){
    this.setData({
      'push.isLoading': true,
      'push.pullText': '正在加载',
    })
    //判断是否存在下一页 后端返回的字段 hasNextPage 
    if (this.data.hasNextPage) {
      this.setData({
        'push.isLoading': false,
        'push.pullText': '- 上拉加载更多 -',
      })
    this.getArticleList(this.data.current+1,this.data.typeId,false);  //调用接口 请求第二页或其他页的数据
    }else{
      setTimeout(() => {
        this.setData({
          'push.isLoading': false,
          'push.pullText': '没有更多了',
        })
      }, 1000);
    }
  },

第一次遇到这个坑 解决起来很麻烦 分享只为更多的朋友提供方便 毕竟每次有坑能够被解决也是一种成长的经历~

本文地址:https://blog.csdn.net/weixin_43703491/article/details/107160068