小程序文章列表超出1024kb的解决方案兼容ios和安卓
最近开发小程序,应客户的需求,在这个小程序官方自带的深坑里摸爬滚打了很久,为的就是解决文章列表翻页加载更多数据,数据的大小超过了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 +'¤t=' +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的标签,是因为之前使用bindtouchstart和bindtouchend会导致页面始终存在卡顿 安卓和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