当前位置: 移动技术网 > 移动技术>移动开发>IOS > 小程序文章列表超出1024kb的解决方案兼容ios和安卓

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

2020年07月08日  | 移动技术网移动技术  | 我要评论

最近开发小程序,应客户的需求,在这个小程序官方自带的深坑里摸爬滚打了很久,为的就是解决文章列表翻页加载更多数据,数据的大小超过了1024KB的解决方案。
先上图,为了实现无限翻页,小程序不会因为setData数据量过大而白屏崩溃

唯一要注意的是,此处的顶部导航栏是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

如对本文有疑问, 点击进行留言回复!!

相关文章:

验证码:
移动技术网