|
|
<template>
|
|
|
<div ref="scroll" class="aaa">
|
|
|
<div ref="listBlock"
|
|
|
:scroll-events="['scroll', 'scroll-end', 'before-scroll-start']"
|
|
|
@scroll="onScrollHandle"
|
|
|
@scroll-end="onScrollEndHandle"
|
|
|
@before-scroll-start="beforeScrollStartHandle"
|
|
|
v-bind="$attrs" v-on="$listeners">
|
|
|
|
|
|
<div class="infinite-list-block" :class="{'list-scroll': scrolling}">
|
|
|
<div class="infinite-list-chunk"
|
|
|
v-for="(chunk, chunkIndex) in visibleList"
|
|
|
:key="chunkIndex"
|
|
|
:data-chunk-id="chunkIndex"
|
|
|
:style="`${chunk.hide ? 'height:' + chunk.height + 'px' : ''}`">
|
|
|
<template v-if="!chunk.hide">
|
|
|
<div class="infinite-list-item"
|
|
|
v-for="(item, index) in chunk.chunkList"
|
|
|
:key="`${chunkIndex}-${index}`">
|
|
|
<slot name="item" :data="item"></slot>
|
|
|
</div>
|
|
|
</template>
|
|
|
</div>
|
|
|
</div>
|
|
|
<div class="list-footer">
|
|
|
<Loading v-show="!noMore" class="load-icon" :size="20"></Loading>
|
|
|
<p v-show="noMore" class="list-nomore">
|
|
|
没有更多了
|
|
|
</p>
|
|
|
</div>
|
|
|
</div>
|
|
|
</div>
|
|
|
</template>
|
|
|
|
|
|
<script>
|
|
|
import {Scroll, Loading} from 'cube-ui';
|
|
|
import {chunk, takeRight, forEach} from 'lodash';
|
|
|
|
|
|
export default {
|
|
|
name: 'InfiniteList',
|
|
|
data() {
|
|
|
return {
|
|
|
scrolling: false,
|
|
|
list: [],
|
|
|
visibleList: [],
|
|
|
chunkSize: 10,
|
|
|
currentIndex: 0,
|
|
|
startOffset: 0,
|
|
|
noMore: false
|
|
|
};
|
|
|
},
|
|
|
props: {
|
|
|
offset: {
|
|
|
type: Number,
|
|
|
default: 100
|
|
|
},
|
|
|
onFetch: {
|
|
|
type: Function,
|
|
|
required: true
|
|
|
},
|
|
|
thumbs: {
|
|
|
type: Array,
|
|
|
default() {
|
|
|
return [];
|
|
|
}
|
|
|
}
|
|
|
},
|
|
|
watch: {
|
|
|
list(newV, oldV) {
|
|
|
let index = oldV.length;
|
|
|
|
|
|
if (newV.length <= index) {
|
|
|
index = 0;
|
|
|
}
|
|
|
|
|
|
this.updateList(index);
|
|
|
}
|
|
|
},
|
|
|
mounted() {
|
|
|
this.scrollHeight = this.$el.offsetHeight;
|
|
|
this.$refs.scroll.onscroll = () => {
|
|
|
console.log(this.$refs.scroll.scrollTop);
|
|
|
console.log(this.$refs.listBlock.scrollTop);
|
|
|
};
|
|
|
this.getData();
|
|
|
this.updateList();
|
|
|
},
|
|
|
methods: {
|
|
|
updateList(index) {
|
|
|
let list = this.visibleList;
|
|
|
|
|
|
if (!Number(index)) {
|
|
|
index = 0;
|
|
|
list = [];
|
|
|
}
|
|
|
|
|
|
let chunks = [];
|
|
|
|
|
|
if (this.list.length) {
|
|
|
chunk(takeRight(this.list, this.list.length - index), this.chunkSize).forEach(val => {
|
|
|
chunks.push({
|
|
|
chunkList: val
|
|
|
});
|
|
|
});
|
|
|
}
|
|
|
|
|
|
this.visibleList = list.concat(chunks);
|
|
|
|
|
|
setTimeout(() => {
|
|
|
// this.$refs.scroll.refresh();
|
|
|
}, 100);
|
|
|
},
|
|
|
getData() {
|
|
|
this.onFetch().then((res) => {
|
|
|
if (!res) {
|
|
|
this.noMore = true;
|
|
|
} else {
|
|
|
this.list = this.list.concat(res);
|
|
|
}
|
|
|
});
|
|
|
},
|
|
|
onScrollHandle() {
|
|
|
|
|
|
},
|
|
|
onScrollEndHandle(scroll) {
|
|
|
if (1000 - scroll.y > this.$refs.listBlock.offsetHeight) {
|
|
|
this._timer && clearTimeout(this._timer);
|
|
|
this._timer = setTimeout(() => {
|
|
|
this.getData();
|
|
|
}, 50);
|
|
|
}
|
|
|
|
|
|
this.clacViewChunks(-scroll.y)
|
|
|
this.scrolling = false;
|
|
|
},
|
|
|
beforeScrollStartHandle() {
|
|
|
this.scrolling = true;
|
|
|
},
|
|
|
clacViewChunks(top) {
|
|
|
if (this.list.length < 50) {
|
|
|
return;
|
|
|
}
|
|
|
//
|
|
|
|
|
|
let time = new Date();
|
|
|
|
|
|
let $children = this.$refs.listBlock.children;
|
|
|
let height = 0;
|
|
|
let hasChange = false;
|
|
|
|
|
|
forEach($children, (dom, index) => {
|
|
|
let chunk = this.visibleList[index];
|
|
|
let hide = false;
|
|
|
let h = dom.offsetHeight;
|
|
|
|
|
|
if (height > top + this.scrollHeight * 5 || height + h < top - this.scrollHeight * 4) {
|
|
|
hide = true;
|
|
|
}
|
|
|
|
|
|
if (!!chunk.hide !== hide) {
|
|
|
hasChange = true;
|
|
|
chunk.hide = hide;
|
|
|
chunk.height = h;
|
|
|
}
|
|
|
|
|
|
height += h;
|
|
|
});
|
|
|
|
|
|
if (hasChange) {
|
|
|
time = new Date();
|
|
|
this.visibleList = [...this.visibleList];
|
|
|
// this.$nextTick(() => {
|
|
|
// alert(new Date() - time);
|
|
|
// });
|
|
|
}
|
|
|
|
|
|
console.log(hasChange);
|
|
|
}
|
|
|
},
|
|
|
components: {
|
|
|
Scroll,
|
|
|
Loading
|
|
|
}
|
|
|
};
|
|
|
</script>
|
|
|
|
|
|
<style lang="scss">
|
|
|
.aaa {
|
|
|
height: 100%;
|
|
|
overflow: scroll;
|
|
|
}
|
|
|
|
|
|
.list-scroll {
|
|
|
position: relative;
|
|
|
|
|
|
&:after {
|
|
|
content: '';
|
|
|
position: absolute;
|
|
|
left: 0;
|
|
|
right: 0;
|
|
|
top: 0;
|
|
|
bottom: 0;
|
|
|
z-index: 1;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
.list-footer {
|
|
|
text-align: center;
|
|
|
padding: 20px;
|
|
|
|
|
|
> * {
|
|
|
display: inline-block;
|
|
|
}
|
|
|
}
|
|
|
</style> |