console
const ListView = {
name: 'ListView',
template: '#list-template',
props: {
data: {
type: Array,
required: true
},
itemSizeGetter: {
type: Function
}
},
computed: {
contentHeight() {
const { data, itemSizeGetter } = this;
let total = 0;
for (let i = 0, j = data.length; i < j; i++) {
total += itemSizeGetter.call(null, data[i], i);
}
return total;
}
},
mounted() {
this.updateVisibleData();
},
data() {
return {
visibleData: [],
index:1
};
},
methods: {
getItemSizeAndOffset(index) {
const { data, itemSizeGetter } = this;
let total = 0;
for (let i = 0, j = Math.min(index, data.length - 1); i <= j; i++) {
const size = itemSizeGetter.call(null, data[i], i);
if (i === j) {
return {
offset: total,
size
};
}
total += size;
}
return {
offset: 0,
size: 0
};
},
findNearestItemIndex(scrollTop) {
const { data, itemSizeGetter } = this;
let total = 0;
for (let i = 0, j = data.length; i < j; i++) {
const size = itemSizeGetter.call(null, data[i], i);
total += size;
if (total >= scrollTop || i === j -1) {
return i;
}
}
return 0;
},
updateVisibleData(scrollTop) {
scrollTop = scrollTop || 0;
const start = this.findNearestItemIndex(scrollTop);
const end = this.findNearestItemIndex(scrollTop + this.$refs.list.clientHeight);
this.visibleData = this.data
console.log(start)
if(start>0){
this.index=1
}
if(start>1000){
this.index=2
}
if(start>2000){
this.index=3
}
if(start>3000){
this.index=4
}
this.visibleData = this.data.slice(start, Math.min(end + 1, this.data.length));
this.$refs.content.style.webkitTransform = `translate3d(0, ${ this.getItemSizeAndOffset(start).offset }px, 0)`;
},
handleScroll() {
const scrollTop = this.$refs.list.scrollTop;
this.updateVisibleData(scrollTop);
}
}
};
new Vue({
components: {
ListView
},
methods: {
itemSizeGetter(item) {
return 30 + item.value % 10;
}
},
data() {
const data = [];
for (let i = 0; i < 10000; i++) {
data.push({ value: i });
}
return {
data
};
}
}).$mount('#app')
<script type="text/x-template" id="list-template">
<div>
<ul class="list-view-right">
<li :class="{isActive:index===item}" v-for="item in 4">{{item}}</li>
</ul>
<div
class="list-view"
ref="list"
@scroll="handleScroll">
<div
class="list-view-phantom"
:style="{
height: contentHeight + 'px'
}">
</div>
<div
ref="content"
class="list-view-content">
<div
class="list-view-item"
:style="{
height: itemSizeGetter(item) + 'px'
}"
:key="index"
v-for="(item, index) in visibleData">
{{ item.value }}
</div>
</div>
</div>
</div>
</script>
<div id="app">
<template>
<list-view
:item-size-getter="itemSizeGetter"
:estimated-item-size="30"
:data="data"></list-view>
</template>
</div>
.list-view {
height: 400px;
overflow: auto;
position: relative;
border: 1px solid #666;
}
.list-view-right{
float: left;
}
.list-view-phantom {
position: absolute;
left: 0;
top: 0;
right: 0;
z-index: -1;
}
.list-view-content {
left: 0;
right: 0;
top: 0;
position: absolute;
}
.list-view-item {
padding: 5px;
color: #666;
height: 30px;
line-height: 30px;
box-sizing: border-box;
border:1px solid red;
}
.isActive{
color:red;
}