mpvue微信小程序长列表
mpvue微信小程序长列表
解决数据过多导致小程序白屏等问题。优化性能。
github demo地址
<scroll-view
scroll-y
class="main-box"
:style="{height:systemHeight+'px'}"
@scrolltolower="handleToBottom"
@scroll="onScroll"
lower-threshold="300rpx"
>
<!-- 全部内容盒子高度 -->
<div class="scroll-box" :style="{height:allBoxHeight+'px'}">
<!-- 可视区域盒子 -->
<div class="scroll-main" :style="{top:top+'px'}">
<card v-for="(item,i) in forEachArr" :key="i" :text="item" />
</div>
</div>
</scroll-view>
话不多说,先贴代码
使用小程序scroll-view标签,监听滚动onScroll和触底事件handleToBottom,设置距离底部 lower-threshold=”300rpx”时触发触底事件,使用变量systemHeight去适应各设备屏幕大小。其中card 是封装的内容组件,通过数据循环出来。
在onLoad生命周期中获取各设备屏幕大小并赋值给变量systemHeight
onLoad() {
this.queryList();// 请求数据
wx.getSystemInfo({
success: res => {
this.systemHeight = res.windowHeight;
}
});
}
全部内容盒子高度由请求回的所有数据条数*每条数据盒子card组件的高控制(接口使用的之前在网上找到的一位哥们的,不知道是否涉权啥的,如有请联系删除:3144739622@qq.com,多谢)
// 请求数据
queryList() {
if (!this.isdisabaled) {
wx.showLoading({ title: "加载中..." });
this.isdisabaled = true;
wx.request({
url: "https://w.taopaitang.com/api/discover",
method: "GET",
data: this.queryData,
header: {
"content-type": "application/json" // 默认值
},
dataType: "json",
success: res => {
wx.hideLoading();
if (res.data.code !== 200) {
wx.showToast({
title: res.data.message,
icon: "none",
duration: 2000,
mask: true
});
} else {
let data = res.data.data.items;
if (this.queryData.page === 1) {
this.allDataArr = data;
} else {
this.allDataArr = this.allDataArr.concat(data);
}
this.computedShowData();
this.isdisabaled = false;
}
}
});
}
}
每次触底时,页码+1,都去请求一次这个方法,并将数据push进去,然后再触发computedShowData方法,计算出实际显示的数据有哪些,可视区域盒子 距离 全部内容盒子 的高度
// 计算显示数据及显示盒子距顶部距离
computedShowData() {
this.allBoxHeight = this.allDataArr.length * this.itemHeight; // 计算全部内容盒子的高度(所有数据条数*每条数据盒子card组件的高)
let {
queryData: { page, pagenum },
showLen,
currentPage
} = this;
if (currentPage < showLen) {
this.top = 0;
this.forEachArr = this.allDataArr.slice(0, showLen * pagenum);
} else {
// 加一是为了将显示内容区域显示在屏幕中,否则无法触发触底事件
this.top = (currentPage + 1 - showLen) * pagenum * this.itemHeight;
this.forEachArr = this.allDataArr.slice(
(currentPage - 2) * pagenum,
currentPage * pagenum
);
}
console.log("this.forEachArr", this.forEachArr);
}
每次向上滚动时怎么计算呢,其实是在之前提到的滚动事件中处理的。每次滚动时,去计算出当前的滚动条是处于哪个page的,处于哪一页,我们就取出相对应的数据显示在可视区域中
// 滚动条
onScroll(val) {
let currentHeight = val.target.scrollTop + this.systemHeight;
// 计算每一页数据的高度
let onePageHeight = this.itemHeight * this.queryData.pagenum;
// 现在显示的数据的页数
if (currentHeight < onePageHeight) {
this.currentPage = 1;
} else {
this.currentPage = Math.ceil(currentHeight / onePageHeight);
}
console.log(
"currentPage",
this.currentPage,
currentHeight,
onePageHeight
);
},
监听每次滚动时页码page如果有变化就触发之前的计算事件computedShowData
watch: {
currentPage(newVal, oldVal) {
console.log("newVal, oldVal", newVal, oldVal);
if (newVal < oldVal) {
this.computedShowData();
} else {
if (newVal <= this.queryData.page) {
this.computedShowData();
}
}
}
}
好了,大概思路就是这样,有需要demo的点这里。全部代码:
index.vue
<template>
<scroll-view
scroll-y
class="main-box"
:style="{height:systemHeight+'px'}"
@scrolltolower="handleToBottom"
@scroll="onScroll"
lower-threshold="300rpx"
>
<!-- 全部内容盒子高度 -->
<div class="scroll-box" :style="{height:allBoxHeight+'px'}">
<!-- 可视区域盒子 -->
<div class="scroll-main" :style="{top:top+'px'}">
<card v-for="(item,i) in forEachArr" :key="i" :text="item" />
</div>
</div>
</scroll-view>
</template>
<script>
import card from "@/components/card";
export default {
data() {
return {
forEachArr: [], // 显示数据
allDataArr: [], // 全部数据
allBoxHeight: 0, // 全部内容盒子高度
top: 0, // 可视区域盒子距离顶部距离
queryData: {
platform: "ZPo4MV4TqsLfAHkist6wQai7S8tzDVmz",
page: 1,
pagenum: 10 // 每页条数
},
showLen: 3, // 显示数据页数
currentPage: 1, // 当前滑动到的页数
itemHeight: 200, // 以各手机屏幕最低高度
systemHeight: 0, // 设备屏幕高度
isdisabaled: false
};
},
watch: {
currentPage(newVal, oldVal) {
console.log("newVal, oldVal", newVal, oldVal);
if (newVal < oldVal) {
this.computedShowData();
} else {
if (newVal <= this.queryData.page) {
this.computedShowData();
}
}
}
},
methods: {
// 请求数据
queryList() {
if (!this.isdisabaled) {
wx.showLoading({ title: "加载中..." });
this.isdisabaled = true;
wx.request({
url: "https://w.taopaitang.com/api/discover",
method: "GET",
data: this.queryData,
header: {
"content-type": "application/json" // 默认值
},
dataType: "json",
success: res => {
wx.hideLoading();
if (res.data.code !== 200) {
wx.showToast({
title: res.data.message,
icon: "none",
duration: 2000,
mask: true
});
} else {
let data = res.data.data.items;
if (this.queryData.page === 1) {
this.allDataArr = data;
} else {
this.allDataArr = this.allDataArr.concat(data);
}
this.computedShowData();
this.isdisabaled = false;
}
}
});
}
},
// 触底 ***必须异步
async handleToBottom() {
this.queryData.page += 1;
await this.queryList();
},
// 滚动条
onScroll(val) {
let currentHeight = val.target.scrollTop + this.systemHeight;
// 计算每一页数据的高度
let onePageHeight = this.itemHeight * this.queryData.pagenum;
// 现在显示的数据的页数
if (currentHeight < onePageHeight) {
this.currentPage = 1;
} else {
this.currentPage = Math.ceil(currentHeight / onePageHeight);
}
console.log(
"currentPage",
this.currentPage,
currentHeight,
onePageHeight
);
},
// 计算显示数据及显示盒子距顶部距离
computedShowData() {
this.allBoxHeight = this.allDataArr.length * this.itemHeight;
let {
queryData: { page, pagenum },
showLen,
currentPage
} = this;
if (currentPage < showLen) {
this.top = 0;
this.forEachArr = this.allDataArr.slice(0, showLen * pagenum);
} else {
// 加一是为了将显示内容区域显示在屏幕中,否则无法触发触底事件
this.top = (currentPage + 1 - showLen) * pagenum * this.itemHeight;
this.forEachArr = this.allDataArr.slice(
(currentPage - 2) * pagenum,
currentPage * pagenum
);
}
console.log("this.forEachArr", this.forEachArr);
}
},
onLoad() {
this.queryList();// 请求数据
wx.getSystemInfo({
success: res => {
this.systemHeight = res.windowHeight;
}
});
},
components: {
card
}
};
</script>
<style scoped>
.main-box .scroll-box {
position: relative;
width: 100%;
}
.main-box .scroll-box .scroll-main {
position: absolute;
left: 0;
width: 100%;
}
</style>
card.vue
<template>
<div>
<div class="card">
<p>{
{text.desc}}</p>
<img :src="text.imgUrl" />
</div>
</div>
</template>
<script>
export default {
props: ["text"]
};
</script>
<style>
.card {
display: flex;
padding: 20rpx;
text-align: center;
/* height: 570rpx; */
}
.card img {
width: 640rpx;
height: 480rpx;
}
</style>
还没有评论,来说两句吧...