<script>
export default {
name: "VirtualList",
props: {
templateRender: Function,list: { type: Array, default: () => [],},remainList: { type: Array, default: () => [],},itemHeight: { type: Number, default: 34,},wrapHeight: { type: Number, default: 262,},group: { type: Number, default: 1,},
},
data() {
return { pointer: 0, translateY: 0,};
},
watch: {
remainList: { handler(v) { this.translateY = v.length * this.itemHeight; let scrollTop = this.$refs["virtual-list-wrapper"]?.scrollTop; if (scrollTop !== undefined) { this.handleScroll({ srcElement: { scrollTop, }, }); } }, immediate: true,},
},
computed: {
scrollHeight() { return ( // (this.groupRemainList.length + this.groupList.length) * this.itemHeight this.groupList.length * this.itemHeight );},displayCount() { return Math.ceil(this.wrapHeight / this.itemHeight);},groupRemainList() { return this.convertByGroup(this.remainList);},groupList() { return this.convertByGroup(this.list);},displayList() { return this.groupList.slice( this.pointer, this.pointer + this.displayCount + 1 );},remainHeight() { return 0; //this.remainList.length * this.itemHeight;},
},
methods: {
convertByGroup(list) { let result = []; let temp = []; list.forEach((data) => { temp.push(data); if (temp.length >= this.group) { result.push(temp); temp = []; } }); if (temp.length > 0) { result.push(temp); } return result;},renderListItem(h, datas, index, startTranslateY, tag) { return h( "div", { class: "virtual-list-item", style: { height: this.itemHeight + "px", transform: `translate3d(0, ${ startTranslateY + index * this.itemHeight }px, 0)`, display: tag === "remian" ? "none" : "block", }, key: tag + index, }, datas.map((data) => { return this.templateRender(h, data, tag); }) );},handleScroll(e) { let scrollTop = e.srcElement.scrollTop; // let remainHeight = this.remainList.length * this.itemHeight; if (scrollTop <= this.remainHeight) { this.pointer = 0; this.translateY = this.remainHeight; } else { // this.translateY = scrollTop; this.pointer = Math.floor( (scrollTop - this.remainHeight) / this.itemHeight ); this.translateY = this.pointer * this.itemHeight + this.remainHeight; }},
},
render(h) {
let children = [ // 要保留的数据 ...this.groupRemainList.map((datas, index) => { return this.renderListItem(h, datas, index, 0, "remian"); }), // 全副数据 ...this.displayList.map((datas, index) => { return this.renderListItem(h, datas, index, this.translateY, "list"); }),];return h( "div", { class: "virtual-list-wrapper", style: { height: this.wrapHeight + "px", }, on: { scroll: this.handleScroll, }, ref: "virtual-list-wrapper", }, [ h( "div", { style: { height: this.scrollHeight + "px", position: "relative", }, }, children ), ]);
},
};
</script>
<style>
.virtual-list-wrapper {
overflow: auto;
}
.virtual-list-item {
position: absolute;
top: 0;
left: 0;
width: 100%;
}
</style>