别人的实现思路
推进方式1:初始化的时候
1 .一些数据的初始加功
_listData() {
return this.listData.map((item, index) => {
return {
_index: `_${index}`,
item
};
});
//把所有的数据都加上一个index序号
visibleCount() {
return Math.ceil(this.screenHeight / this.estimatedItemSize);
},
//计算一张页面显示的数据
visibleData() {
return this._listData.slice(this.start, this.end);
}
//实际显示的数据
//这些都是在computed里面,会自动计算
initPositions() {
this.positions = this.listData.map((d, index) => ({
index,
height: this.estimatedItemSize,
top: index * this.estimatedItemSize,
bottom: (index + 1) * this.estimatedItemSize
}));
},
//根据初始数据,算出默认的高度,以及默认的间隔
2 .根据数据渲染完数据的时候
this.$nextTick(function() {
if (!this.$refs.items || !this.$refs.items.length) {
return;
}
//获取真实元素大小,修改对应的尺寸缓存
this.updateItemsSize();
//更新列表总高度
let height = this.positions[this.positions.length - 1].bottom;
this.$refs.phantom.style.height = height + "px";
//更新真实偏移量
this.setStartOffset();
});
//计算当前的显示元素的高度,更新里面默认的存储的高度.这个是他的实现的特色
//计算当前所有元素的高度并更新
updateItemsSize() {
let nodes = this.$refs.items;
nodes.forEach(node => {
let rect = node.getBoundingClientRect();
let height = rect.height;
let index = +node.id.slice(1);
let oldHeight = this.positions[index].height;
let dValue = oldHeight - height;
//存在差值:就是这个当前的高度和里面存的数据有差池,更新数据
if (dValue) {
this.positions[index].bottom = this.positions[index].bottom - dValue;
this.positions[index].height = height;
for (let k = index + 1; k < this.positions.length; k++) {
//这里需要更新这个数据后面的所有数据的高度
this.positions[k].top = this.positions[k - 1].bottom;
this.positions[k].bottom = this.positions[k].bottom - dValue;
}
}
});
},
//这里有两个感觉不太好的地方,其一就是每次都需要把当前的都算一遍,之前算过的也要在算一遍,如果算过的话,就不用再算了,其二就是当发现有变化,不仅这个数据的数据需要更新,后面的所有数据也需要一并更新,这样如果总的数据很大的话,不知道计算时间是多少,会不会造成页面的卡顿
推进方式2:滚动的时候
let scrollTop = this.$refs.list.scrollTop;
//此时的开始索引
this.start = this.getStartIndex(scrollTop);
//此时的结束索引
//这里有个二分法查询数据的算法
this.end = this.start + this.visibleCount;
//此时的偏移量
//改变start,end。
this.setStartOffset();
二分查找算法
binarySearch(list, value) {
let start = 0;
let end = list.length - 1;
let tempIndex = null;
while (start <= end) {
let midIndex = parseInt((start + end) / 2);
let midValue = list[midIndex].bottom;
if (midValue === value) {
return midIndex + 1;
} else if (midValue < value) {
start = midIndex + 1;
} else if (midValue > value) {
if (tempIndex === null || tempIndex > midIndex) {
tempIndex = midIndex;
}
end = end - 1;
}
}
return tempIndex;
}
场景升级版本
1 .需要动态新增数据,并不是一开始就有所有数据
2 .每次新增数据都需要滚动到显示最新数据