//temple部分
<template>
<!-- 本頁面是虛擬加載組件,還有個長列表懶加載組件(sickListPageLoad.vue)。 -->
<view class="sickBody">
<scroll-view scroll-y="true" class="scroll-Y" @scroll="scroll">
<view class="parentDom">
<!-- <view :style="{ height: sickAllList.length * 40 + 'px' }"></view> -->
<view :style="{ height: screenHeight + 'px' }"></view>
<view class="positionRelative" :style="{ transform: getTransform }">
<view v-for="item in visibleData" :key="item.id" class="height40" @click="choseSick(item)">{{
item.name
}}</view>
</view>
</view>
</scroll-view>
</view>
</template>
js部分
let testdata = [];
for (let i = 0; i < 300; i++) {
testdata.push({ id: i, name: '疾病' + i });
}
/**
* 搜索組件
*/
import { throttle } from '@/utils/optimize'; //防抖,自己寫一個
export default {
props: {
// 是否展示搜索按鈕
listData: {
type: Array,
default: () => []
},
itemSize: {
type: Number,
default: 40
}
},
data() {
return {
searchList: [],
// screenHeight: 1200,
startOffset: 0,
start: 0,
end: 20,
scrollTData: 0,
count: 20,
remain: 8
// testData: []
};
},
computed: {
listHeight() {
return testdata.length * this.itemSize;
},
screenHeight() {
return testdata.length * Number(this.itemSize) + 100;
},
// 前面預留幾個
prevCount() {
return Math.min(this.start, this.remain);
},
// 后面預留幾個
nextCount() {
return Math.min(this.remain, this.end);
},
getTransform() {
return `translate3d(0,${this.startOffset}px,0)`;
},
visibleData() {
return testdata.slice(this.start, Math.min(this.end, testdata.length));
}
},
mounted() {
this.sickAllList = testdata;
},
methods: {
close() {
this.$emit('popClose');
},
center() {
this.$emit('popCenter');
},
go_search() {
this.$wxPromise.navigateTo({
url: '/pages/searchDrug/index'
});
},
choseSick(item) {
this.$emit('choseSickSearch', item);
},
scroll(e) {
this.scrollTData = e.target.scrollTop;
this.scrollThrottle();
},
/* eslint-disable */
scrollThrottle: throttle(function () {
// uni.showLoading({
// title: '加載中',
// mask: true
// });
let scrollTop = this.scrollTData; // e.target.scrollTop;
// 此時的開始索引
this.start =
Math.floor(scrollTop / this.itemSize) - this.prevCount >= 0
? Math.floor(scrollTop / this.itemSize) - this.prevCount
: 0;
// 此時的結束索引
this.end = Number(this.start) + Number(this.count) + Number(this.nextCount);
// 此時的偏移量
// console.log('位置', this.start, this.end);
this.startOffset = Number(this.start) * Number(this.itemSize);
}, 0)
}
};
樣式
<style lang="scss">
.sickBody {
position: fixed;
left: 0;
top: 0;
width: 100%;
height: 100%;
background: #f4f4f4;
z-index: 99;
}
.infinite-list-container {
height: 100%;
overflow: auto;
position: relative;
-webkit-overflow-scrolling: touch;
}
.infinite-list-phantom {
position: absolute;
left: 0;
top: 0;
right: 0;
z-index: -1;
}
.infinite-list {
left: 0;
right: 0;
top: 0;
position: absolute;
text-align: center;
}
.infinite-list-item {
padding: 10px;
color: #555;
box-sizing: border-box;
border-bottom: 1px solid #999;
}
.scroll-Y {
height: 100%;
overflow-y: scroll;
}
.height40 {
height: 39px;
line-height: 39px;
width: 100%;
overflow: hidden;
border-bottom: 1px solid #d2d2d2;
}
.positionRelative {
width: 92%;
margin: 0 3%;
position: absolute;
left: 0;
top: 0;
font-size: 32rpx;
padding-bottom: 300rpx;
// height: 100%;
// width: 100%;
}
.parentDom {
position: relative;
}
</style>
總結
總結:
思路很簡單:
一、 拿到所有數據應該占用的高度。比如1萬條數據,每條占40px,占用高度應為1萬*40;
二、拿到展示區域的高度,比如我想展示50條數據,展示高度即為50*40;
三、拿到屏幕滾動的距離,用滾動的距離/行高,獲取當前第一行應該展示對應數據的下標值,比如滾動了400px,當前展示的第一條數據的下標應為10
四、截取需要展示的數據:this.testData.slice(this.start, Math.min(this.end, this.testData.length)); 注意前后預留數據,要不然會有空白出現
五、完工
注意事項:一定要脫離標准文檔流,給展示區域加定位position:absolute。要不然回流會讓你電腦崩潰。里面要不要加節流防抖等細節可以自己看着加。我初期嘗試加了節流,加了反而可能造成數據更新會缺少n條,滑動有延遲了,數據被節流了。