https://github.com/tangbc/vue-virtual-scroll-list
<!DOCTYPE html><html lang="zh"><head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><meta http-equiv="X-UA-Compatible" content="ie=edge"><style>.wrapper {height: 100%;overflow: auto;}.item {height: 50px;padding-left: 50px;}</style></head><body><div id="app"><div class="wrapper" ref="wrapper" @scroll="handleScroll" :style="{ height: height + 'px' }"><div ref="w"><div :style="{ height: `${shimTopOffset}px` }"></div><divclass="item"v-for="item in showList":key="item.index":style="{height: `${itemHeight}px`,color: item.color,}">{{ item.index }}</div><div :style="{ height: `${shimBottomOffset}px` }"></div></div></div></div><script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script><script>new Vue({el: '#app',data() {return {height: 500,itemHeight: 50,data: Array.from({ length: 6000 }).map((_, index) => ({index,color: `#${Math.random().toString(16).substr(2, 6)}`,})),showList: [],shimTopOffset: 0,shimBottomOffset: 0,};},mounted() {this.update(0);this.$nextTick(() => {this.maxHeight = this.$refs.w.offsetHeight;});},methods: {handleScroll() {const scrollTop = this.$refs.wrapper.scrollTop;if (scrollTop >= 0 && scrollTop + this.height <= this.maxHeight) {window.requestAnimationFrame(() => {this.update(scrollTop);});}},update(scrollTop) {const visibleStart = scrollTop;const visibleEnd = scrollTop + this.height;this.showList = this.getShowList(visibleStart, visibleEnd, this.data);},getShowList(start, end, data) {if (start < end) {const lo = this.getStartIndex(start, this.itemHeight);const hi = this.getEndIndex(end, this.itemHeight);this.shimTopOffset = lo >= 0 ? lo * this.itemHeight : 0;this.shimBottomOffset = hi >= 0 ? (data.length - hi) * this.itemHeight : 0;return data.slice(lo, hi);} else {this.shimTopOffset = 0;this.shimBottomOffset = 0;return [];}},getStartIndex(s, itemHeight) {const startIndex = ~~(s / itemHeight);return startIndex >= 0 ? startIndex : 0;},getEndIndex(e, itemHeight) {const endIndex = Math.ceil(e / itemHeight);return endIndex <= this.data.length ? endIndex : this.data.length;},},watch: {data: {handler(newVal, oldVal) {if (oldVal) {this.$nextTick(() => {this.$refs.wrapper.scrollTop = 0;this.handleScroll();});}},immediate: true,},itemHeight() {this.handleScroll();},},})</script></body></html>
