Skip to content

虚拟列表 xVirtualList


在线预览
在线模拟尺寸:

介绍

这是一个超高虚拟列表,无论几万数据都能轻松应对是你列表处理数据的不二之选,集成下拉刷新,触底更新,指定索引位置等。 未来将应于表格,picker等系列组件,作为其它组件的底层存在,极大提高性能。使用时请注意demo示例使用方法。

平台兼容

H5andriodIOS小程序UTSUNIAPP-X SDKversion
☑️☑️☑️☑️4.44+1.1.14

文件路径

ts

@/uni_modules/tmx-ui/components/x-virtual-list/x-virtual-list.uvue

使用

ts

<x-virtual-list></x-virtual-list>

Props 属性

名称说明类型默认值
itemHeight项目高度,不可用auto,只能是数字(默认为px),带单位的rpx,pxstring"50"
viewCount渲染显示多少个,它不是最终的渲染数量,是最少数量,因为内部还有个缓存数量number5
list数据列表Array() => [] as any[]
bufferSize缓冲区大小,在可视区域前后额外渲染的项目数量number2
enableVirtual是否启用虚拟滚动booleantrue
refresherEnabled启用下拉刷新booleanfalse
pullState需要自行管理下拉状态,默认为false,通过事件pull触发设置为true,结束设置为Falsebooleanfalse
refresherBottomEnabled启用触底刷新booleanfalse
bottomState需要自行管理下拉状态,默认为false,通过事件bottom触发设置为true,结束设置为Falsebooleanfalse

Events 事件

名称参数说明
scroll-滚动事件
pull-滚动到顶时触发
bottom-触底时触发
rangeChange-渲染范围变化时触发

Slots 插槽

名称说明数据
stickysticky插槽-
header顶部插槽,仅APP有效,它是nested-scroll-header协商节点,会自动与内容衔接在头上然后自动上往上推。-
default内容插槽你在这里渲染内容data : any[]
data : number
data : number
startIndex : any[]
startIndex : number
startIndex : number
endIndex : any[]
endIndex : number
endIndex : number
bottom底部插槽-

Ref 方法

名称参数返回值说明
scrollToIndex--滚动到指定索引
refreshSize--刷新容器尺寸
resetScroll--重置滚动位置
getRenderRange--获取当前渲染范围
getContainerBounds--获取容器尺寸

示例文件路径

json

/pages/zhanshi/virtual-list

示例源码

uvue
vue
<template>

	<!-- #ifdef MP-WEIXIN -->
	<page-meta :page-style="`background-color:${xThemeConfigBgColor}`">
		<navigation-bar :background-color="xThemeConfigNavBgColor" :front-color="xThemeConfigNavFontColor"></navigation-bar>
	</page-meta>
	<!-- #endif -->
		<x-sheet>
			<x-text font-size="18" class=" text-weight-b mb-8">虚拟列表 xVirtualList</x-text>
			<x-text color="#999999">通过插槽渲染数据,但不要让项目高超过指定的项目高。本页面演示数量为:1万条,打开时间为60ms左右,不存在卡页面情况。</x-text>
			<view class="flex flex-row flex-row-center-between mb-10">
				<x-button class="flex-1" @click="scrollTo" >指定</x-button>
				<x-button class="ml-5 flex-1" @click="reloadData" >追加</x-button>
				<x-button class="mx-5 flex-1" @click="changeData" >20条</x-button>
				<x-button class="flex-1" @click="clearAll" >清空</x-button>
			</view>
		</x-sheet>
		<x-virtual-list 
		v-if="list.length>0"
		ref="virtual" 
		:pullState="pullState"
		:bottomState="bottomState"
		@pull="onpull"
		@bottom="bottomLoad"
		:refresherEnabled="true"
		:refresherBottomEnabled="true"
		style="flex: 1;margin: 0 16px;" itemHeight="80" :list="list">
			<template v-slot:sticky>
				<x-sheet :margin="['0']" :round="['0']" color="red">
					<x-text>sticky头</x-text>
				</x-sheet>
			</template>
			<!-- 仅APP显示和兼容 -->
			<template v-slot:header>
				<x-sheet :margin="['0']" :round="['0']">
					<x-text>子协商头,具体体验由官方底层决定</x-text>
				</x-sheet>
			</template>
			<template v-slot:default="{data,startIndex,endIndex}">
				<view class="item" v-for="(item,index) in (data as UTSJSONObject[])" :key="index" :style="{height:'80px'}">
					<view class="itemWrap flex flex-row flex-row-center-start">
						<!-- 为什么要给图片加key,是因为浏览器它同样的key变动时在vue中是重复的图片加载有个视觉停留,会
						 给人感觉图片虚的变动时好像是旧数据,而app不需要加,因为app图片是缓存读取直接显示更换,没有延迟,给人感觉就是加载动态的数据。
						 -->
						<image 
						class="round-6"
						<!-- #ifdef MP||WEB||APP-HARMONY -->
						:key="item.getAny('id')" 
						<!-- #endif -->
						style="width: 50px;height:50px;" :src="`https://store.tmui.design/api_v2/public/random_picture?random=${item.getAny('id')}`"></image>
						<text class="ml-10" style="font-size:18px">{{item.getAny('text')}}</text>
					</view>
				</view>
			</template>
		</x-virtual-list>
		<x-empty @click="load" btn-label="加载1万条" v-if="list.length==0" :loading="false" :empty="true"></x-empty>

</template>

<script setup>

	// @ts-ignore
	const virtual = ref<XVirtualListComponentPublicInstance|null>(null)
	const list = ref<UTSJSONObject[]>([])
	const pullState = ref(false)
	const bottomState = ref(false)
	function load(){
		let tmeplist = [] as UTSJSONObject[]
		for(let i=0;i<10000;i++){
			tmeplist.push({
				id:i,
				text:`数据项目-${i+1}`
			} as UTSJSONObject)
		}
		list.value = tmeplist
	}
	function reloadData(){
		let tmeplist = [] as UTSJSONObject[]
		for(let i=0;i<20;i++){
			tmeplist.push({
				id:i,
				text:`数据项目-a${i+1}`
			} as UTSJSONObject)
		}
		list.value = [...list.value,...tmeplist] 
	}
	
	function clearAll(){
		pullState.value = false
		bottomState.value = false
		list.value = [] as UTSJSONObject[]
	}
	function changeData(){
		list.value = list.value.slice(0,20)
	}
	
	function onpull(){
		pullState.value = true
		setTimeout(()=>{
			pullState.value = false
		},6020)
	}
	function bottomLoad(){
		bottomState.value = true
		
		setTimeout(()=>{
			bottomState.value = false
			// 加载更多数据
			reloadData()
		},1200)
	}
	
	function scrollTo(){
		virtual.value?.scrollToIndex?.(2)
	}
	onReady(()=>{
		load()
	})
</script>

<style scoped lang="scss">
	.item{
		display: flex;
		flex-direction: column;
		padding-bottom: 5px;
	}
	.itemWrap{
		background-color: white;
		padding: 16px;
		flex: 1;
	}
</style>
最近更新