new Vue({
el: "#scroll-area",
data: {
msg: "滚动",
list: [] ,
reachBottomDistance: 100,
isReachBottom: false,
scrollHeight: 0,
offsetHeight: 0
},
beforeMount() {
this.addNumber();
},
mounted() {
const target = document.getElementById("scroll-area");
this.scrollHeight = target.scrollHeight;
this.offsetHeight = Math.ceil(target.getBoundingClientRect().height);
},
methods: {
onScroll(e) {
const target = e.target;
const scrollTop = target.scrollTop;
if(offsetHeight + scrollTop < this.scrollHeight && this.isReachBottom) {
this.isReachBottom = false;
}
if(this.isReachBottom) {
return;
}
if(offsetHeight + scrollTop + this.reachBottomDistance >= this.scrollHeight) {
this.isReachBottom = true;
console.log("botton");
}
},
addNumber() {
var added = [];
for(var i = 0; i < 50; i ++) {
added.push(Math.random());
}
this.list = this.list.concat(added);
}
}
})
new Vue({
el: ".list-view",
data: {
start: 0,
end: null,
visibleData: [],
visibleCount: null,
itemHeight: 30
},
computed: {
contentHeight() {
return this.allData.length * this.itemHeight + 'px' ;
}
},
beforeCreate() {
let i = 0;
this.allData = [];
while(i < 10000) {
this.allData.push({
value: Math.random()
});
i++;
}
},
mounted() {
this.visibleCount = Math.ceil(this.$el.clientHeight / this.itemHeight);
this.updateVisibleData();
},
methods: {
onScroll(e) {
const scrollTop = this.$el.scrollTop;
this.updateVisibleData(scrollTop);
},
updateVisibleData(scrollTop = 0) {
this.start = Math.floor(scrollTop / this.itemHeight);
this.end = this.start + this.visibleCount;
this.visibleData = this.allData.slice(this.start, this.end);
this.$refs.content.style.webkitTransform = `translate3d(0, ${this.start * this.itemHeight}px, 0)`;
}
}
})
new Vue({
el: ".list-view",
data: {
start: 0,
end: null,
visibleData: []
},
computed: {
contentHeight() {
let total = 0;
this.allData.forEach((item, index) => {
total += this.itemSizeGetter(item, index);
})
return total + 'px' ;
}
},
beforeCreate() {
let i = 0;
this.allData = [];
while(i < 10000) {
this.allData.push({
value: Math.random()
});
i++;
}
this.itemSizeGetter = function(item, index) {
};
},
mounted() {
this.updateVisibleData();
},
methods: {
onScroll(e) {
const scrollTop = this.$el.scrollTop;
this.updateVisibleData(scrollTop);
},
updateVisibleData(scrollTop = 0) {
this.start = this.findNearestItemIndex(scrollTop);
this.end = this.findNearestItemIndex(scrollTop + this.$el.clientHeight);
this.visibleData = this.allData.slice(this.start, this.end + 1);
this.$refs.content.style.webkitTransform = `translate3d(0, ${this.getItemOffset(start)}px, 0)`;
},
findNearestItemIndex(scrollTop) {
let top = 0;
for(let i=0, j = this.allData.length; i<j; i++) {
const size = this.itemSizeGetter(this.allData[i], i);
total += size;
if(total > scrollTop || i === j-1) {
return i;
}
}
return 0;
},
getItemOffset(index) {
for(let i=0, j = Math.min(index, this.allData.length -1); i <= j; i++ ) {
const size = this.itemSizeGetter(this.allData[i], i);
if(i === j) {
return total;
}
total += size;
}
return 0;
}
}
})
new Vue({
el: ".list-view",
data: {
start: 0,
lastMeasuredIndex: -1,
visibleData: [],
sizeAndOffsetCache: {},
estimatedItemSize: 30
},
computed: {
contentHeight() {
let total = 0;
if(this.lastMeasuredIndex >= 0) {
const lastMeasured = this.getLastMeasuredSizeAndOffset();
total = lastMeasured.offset + lastMeasured.size + (this.allData.length -1 - this.lastMeasuredIndex) * this.estimatedItemSize;
}else {
total = this.allData.length * this.estimatedItemSize;
}
return total + 'px' ;
}
},
beforeCreate() {
let i = 0;
this.allData = [];
while(i < 10000) {
this.allData.push({
value: Math.random()
});
i++;
}
this.itemSizeGetter = function(item, index) {
if(index % 2 === 0) {
return 20;
}
return 30;
};
},
mounted() {
this.updateVisibleData();
},
methods: {
onScroll(e) {
const scrollTop = this.$el.scrollTop;
this.updateVisibleData(scrollTop);
},
updateVisibleData(scrollTop = 0) {
this.start = this.findNearestItemIndex(scrollTop);
this.end = this.findNearestItemIndex(scrollTop + this.$el.clientHeight);
this.visibleData = this.allData.slice(this.start, this.end + 1);
this.$refs.content.style.webkitTransform = `translate3d(0, ${this.getItemSizeAndOffset(this.start).offset}px, 0)`;
},
findNearestItemIndex(scrollTop) {
let top = 0;
for(let i=0, j = this.allData.length; i<j; i++) {
const size = this.getItemSizeAndOffset(i).size;
top += size;
if(top > scrollTop || i === j-1) {
return i;
}
}
return 0;
},
getItemSizeAndOffset(index) {
if(this.lastMeasuredIndex >= index) {
return this.sizeAndOffsetCache[index];
}
const lastMeasured = this.getLastMeasuredSizeAndOffset();
let offset = lastMeasured.offset + lastMeasured.size;
for(let i= this.lastMeasuredIndex + 1; i <= index; i++ ) {
const size = this.itemSizeGetter(this.allData[i], i);
this.sizeAndOffsetCache[i] = {
size: size,
offset: offset
};
offset += size;
}
if(index > this.lastMeasuredIndex) {
this.lastMeasuredIndex = index;
}
return this.sizeAndOffsetCache[index];
},
getLastMeasuredSizeAndOffset() {
return this.lastMeasuredIndex >= 0 ? this.sizeAndOffsetCache[this.lastMeasuredIndex] : {
offset: 0,
size: 0
};
}
}
})