Skip to content

虚拟列表 VirtualList

用来展示很长很长很长的列表,只有看到的部分才会被实际渲染。组件在十万数量级的数据下可流畅渲染(更多也可以,但是可能被浏览器 DOM 的最大高度截断内容)。

虚拟列表采用分层次分块策略维护前缀和。这种数据结构能将计算高度的时间复杂度控制在 O(n)O(\sqrt{n}),最终在大数据量场景下实现流畅滚动。

WARNING

浏览器对单个 DOM 的最大可滚动 / 可绘制高度存在实现差异与上限,可能导致内容在极端情况下被裁剪或无法正常滚动。例如:在 Edge 版本 141.0.3537.71 中,页面可展示的像素高度在 2.7 千万像素左右,超过此范围的内容会被截断或不可见。

在使用百万级或更大数据量时,请注意总高度(itemsCount×averageItemHeightitemsCount \times averageItemHeight)是否会接近或超过浏览器的限制。

基础使用

虚拟列表默认子元素动态高度。estimatedHeight 设置初始化时元素的预估高度,通常应该比大部分子元素高度小些。

Item #0
<template>
	<px-virtual-list :list="list" style="height: 500px" :estimated-height="20"></px-virtual-list>
</template>
<script lang="ts" setup>
import { shallowRef, h } from 'vue'

const list = shallowRef(
	Array.from({ length: 10000 })
		.fill(0)
		.map((_, index) => ({
			render: () => h('div', { style: `height: ${20 + index / 100}px;` }, [`Item #${index}`])
		}))
)
</script>

固定高度

虚拟列表的子元素高度固定,或者可以准确获得子元素平均高度时,可以设置 fixedHeightestimatedHeight,节省性能。

Item #0
<template>
	<px-virtual-list
		:list="list"
		style="height: 500px"
		fixed-height
		:estimated-height="20"
	></px-virtual-list>
</template>
<script lang="ts" setup>
import { shallowRef, h } from 'vue'

const list = shallowRef(
	Array.from({ length: 10000 })
		.fill(0)
		.map((_, index) => ({
			render: () => h('div', { style: `height: 20px;` }, [`Item #${index}`])
		}))
)
</script>

API

VirtualListProps

属性类型可选默认值描述版本
list{ render: ValidContent; key?: string | number | symbol }[]用于渲染的数据数组。0.0.3
fixedHeightbooleanfalse是否为定高模式。0.0.3
estimatedHeightnumber28预估项高(用于初始化和测量前的估算),单位 px。0.0.3
buffernumber10缓冲项数,控制视窗前后多渲染的项数以避免快速滚动时闪烁。0.0.3