Vue 虚拟滚动实现原理
已知高度的处理方案
<template> <div class="viewport" ref="viewport" @scroll="handleScroll"> <div class="scroll-bar" ref="scrollBar"> <!-- 可以滚动的容器 --> </div> <div class="scroll-list" :style="{transform: `translate3d(0, ${offset}px, 0)`}"> <!-- 可视区的列表 --> <div v-for="item in visibleData" :key="item.id"> <slot :item="item"></slot> </div> </div> </div> </template> <script> export default { props: { size: { type: Number, default: 0 // 每一项的高度 }, remain: { type: Number, default: 0 // 可视化区域显示多少个 }, items: { type: Array, default: () => [] // 列表 } }, data() { return { start: 0, offset: 0, end: this.remain // 默认显示8个 }; }, computed: { prevCount() { return Math.min(this.start, this.remain) }, nextCount () { // 总个数不足就使用剩下的个数 return Math.min(this.end, this.items.length - this.end) }, visibleData() { let start = this.start - this.prevCount; let end = this.end + this.nextCount; return this.items.slice(start, end); } }, mounted() { this.$refs.viewport.style.height = this.size * this.remain + "px"; this.$refs.scrollBar.style.height = this.items.length * this.size + "px"; }, methods: { handleScroll() { let scrollTop = this.$refs.viewport.scrollTop; // 滚动了多少距离 this.start = Math.floor(scrollTop / this.size); // 第几个开始,向下取整,因为还有即使还有一半没显示也要保留 this.end = this.start + this.remain; // 去掉滚动完成的那几个 this.offset = this.start * this.size - this.size * this.prevCount; // 显示三屏,要减去预留渲染 } } }; </script> <style> .viewport { overflow: auto; position: relative; } .scroll-list { position: absolute; left: 0; top: 0; width: 100%; transform: translate3d(0, 0, 0); } </style>
使用
<template> <div class="hello"> <virtual-list :size="40" :remain="8" :items="items"> <template slot-scope="{item}"> <div class="item"> {{item.value}} </div> </template> </virtual-list> </div> </template>
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论