虚拟滚动列表
1.一次性传入大量数据的情况下,通过滚动数据位置,只显示10条数据
(1)计算可视区域
- 设定每个列表项的高度(如
itemHeight = 50px)。 - 计算可视区域内可显示的最大列表项数量: visibleCount=Math.ceil(视口高度/itemHeight)visibleCount = Math.ceil(视口高度 / itemHeight)visibleCount=Math.ceil(视口高度/itemHeight)
- 示例:
- 视口高度
500px - 每个项
50px - 可视项数
500 / 50 = 10(最多渲染 10 个)
- 视口高度
(2)动态更新 DOM
-
只渲染可视区域的项(
visibleData)。 -
计算 起始索引
startIndex=Math.floor(滚动距离/itemHeight)startIndex = Math.floor(滚动距离 / itemHeight)startIndex=Math.floor(滚动距离/itemHeight) endIndex=startIndex+visibleCountendIndex = startIndex + visibleCountendIndex=startIndex+visibleCountstartIndex和 结束索引endIndex: -
示例:
- 滚动 150px →
startIndex = 150 / 50 = 3 - 可见数量 10 →
endIndex = 3 + 10 = 13 - 仅渲染
list.slice(3, 13),隐藏其它项
- 滚动 150px →
(3)监听滚动事件
- 滚动事件触发后,重新计算
startIndex和endIndex,更新visibleData。 - 通过
transform: translateY()让可视元素的位置匹配滚动位置。
优化:可以计算缓存区防止太快滚动没计算出来
2.通过懒加载的方式,一次性只传入20条,当最后一条数据进入可视区触发重新请求之后的20条数据:
obFooterLoading() { if (!this.bottomLoadMode) return const ob = new IntersectionObserver((entries) => { if (entries[0].intersectionRatio >= 1) { if (this.isLoadingMore) return this.$emit('onLoadMore') } }, { threshold: 1.0, root: document.querySelector('.vl-select-popover') }) ob.observe(document.querySelector('.vl_load_more_trigger')) }
- 监听最后一个元素 是否出现在视口中:
intersectionRatio >= 1表示完全可见,触发onLoadMore事件加载更多数据。
浙公网安备 33010602011771号