uniapp 开发小程序虚拟长列表万条数据不卡顿

1. 页面滚动

在这里插入图片描述

虚拟列表 只对可见区域进行渲染,对非可见区域中的数据不渲染或部分渲染,以实现减少消耗,提高用户体验的技术。它是长列表的一种优化方案,性能良好。当数据体量极大时,使用虚拟列表,可以极大减少节点的渲染,体验丝滑。

<template>
	<view>			
		<!--height值为所有数据总高-->
		<view :style="{height: itemHeight*(listAll.length) + 'px', position: 'relative'}">
			
			<!--可视区域里所有数据的渲染区域-->
			<view :style="{position: 'absolute', top: top + 'px'}">
				
				<!--单条数据渲染区域-->
				<view class="item" v-for="(item,index) in showList" :key="index" >
					<image src="../../static/01.png" mode="aspectFill" style="height: 100px; width: 100px;"></image>
					{{item}}
				</view>
			</view>
		</view>		
	</view>
</template>

<script>
	export default {    
		data(){
			return{
				listAll: [],  //所有数据
				showList: [],  //可视区域显示的数据				
				itemHeight: 105, //每条数据所占高度
				showNum: 10,  //每次加载到可视区域的数量,itemHeight X showNum 要大于屏幕高度 ,否则页面滚动不了。
				top: 0, //偏移量
				scrollTop: 0,  //卷起的高度
				startIndex: 0,  //可视区域第一条数据的索引
				endIndex: 0,  //可视区域最后一条数据后面那条数据的的索引,因为后面要用slice(start,end)方法取需要的数据,但是slice规定end对应数据不包含在里面				
			}
		},
		
		/*页面滚动事件*/
		onPageScroll(e) {						
			this.scrollTop = e.scrollTop			
			this.getShowList()			
		},
		
		onLoad() {
			this.getAllList()
			this.getShowList()
		},
		
		methods:{
			//构造2万条数据
			getAllList(){
				for(let i=0;i<20000;i++){
					this.listAll.push(`我是第${i}号佳丽`)
				}				
			},
			
			//计算可视区域数据
			getShowList(){				
				this.startIndex = Math.floor(this.scrollTop/this.itemHeight);   //可视区域第一条数据的索引
				this.endIndex = this.startIndex + this.showNum;   //可视区域最后一条数据的后面那条数据的索引
				this.showList = this.listAll.slice(this.startIndex, this.endIndex)  //可视区域显示的数据,即最后要渲染的数据。实际的数据索引是从this.startIndex到this.endIndex-1
				this.top = this.scrollTop - (this.scrollTop % this.itemHeight);  //在这需要获得一个可以被itemHeight整除的数来作为item的偏移量,这样随机滑动时第一条数据都是完整显示的
			}
			
			
		}
		
	}
</script>

<style scoped>	
	.item{
		height:105px;
		padding: 5px;
		color: #666;
		box-sizing: border-box;
	}
</style>

2. 区域滚动

在这里插入图片描述

可滚动视图区域 scroll-view 用于区域滚动。需注意在webview渲染的页面中,区域滚动的性能不及页面滚动。
使用竖向滚动时,需要给 一个固定高度,通过 css 设置 height;使用横向滚动时,需要给添加white-space: nowrap;样式。

<template>
	<view>		
		<scroll-view class="scroll-box" scroll-y="true" @scroll="scrollEvent">
			
			<!--可视区域里所有数据的渲染区域-->
			<view :style="{position: 'absolute', top: top + 'px'}">
				
				<!--单条数据渲染区域-->
				<view class="item" v-for="(item,index) in showList" :key="index" >
					<image src="../../static/01.png" mode="aspectFill" style="height: 100px; width: 100px;"></image>
					{{item}}
				</view>
			</view>
		</scroll-view>		
	</view>
</template>

<script>
	export default {    
		data(){
			return{
				listAll: [],  //所有数据
				showList: [],  //可视区域显示的数据				
				itemHeight: 105, //每条数据所占高度
				showNum: 6,  //每次加载到可视区域的数量,itemHeight X showNum 要可视区域高度 ,否则页面滚动不了。
				top: 0, //偏移量
				scrollTop: 0,  //卷起的高度
				startIndex: 0,  //可视区域第一条数据的索引
				endIndex: 0,  //可视区域最后一条数据后面那条数据的的索引,因为后面要用slice(start,end)方法取需要的数据,但是slice规定end对应数据不包含在里面				
			}
		},
				
		onLoad() {
			this.getAllList()
			this.getShowList()
		},
		
		methods:{
			//构造2万条数据
			getAllList(){
				for(let i=0;i<20000;i++){
					this.listAll.push(`我是第${i}号佳丽`)
				}				
			},
			
			//计算可视区域数据
			getShowList(){				
				this.startIndex = Math.floor(this.scrollTop/this.itemHeight);   //可视区域第一条数据的索引
				this.endIndex = this.startIndex + this.showNum;   //可视区域最后一条数据的后面那条数据的索引
				this.showList = this.listAll.slice(this.startIndex, this.endIndex)  //可视区域显示的数据,即最后要渲染的数据。实际的数据索引是从this.startIndex到this.endIndex-1
				this.top = this.scrollTop - (this.scrollTop % this.itemHeight);  //在这需要获得一个可以被itemHeight整除的数来作为item的偏移量,这样随机滑动时第一条数据都是完整显示的
			},
			
			//区域滚动事件
			scrollEvent(e){				
				this.scrollTop = e.detail.scrollTop
				this.getShowList()	
			}
			
			
		}
		
	}
</script>

<style scoped>	
	.item{
		height:105px;
		padding: 5px;
		color: #666;
		box-sizing: border-box;
		
	}
	.scroll-box{
		height: 300px; 
		width: 99%; 
		position: relative; 
		border: 1px solid red;
		margin-top: 100px;
	}
</style>

<think>好的,我现在需要回答用户关于UniApp支持的数组长度的问题。首先,我得回想一下UniApp的基础知识。UniApp是基于Vue.js的跨平台开发框架,主要用于开发小程序、H5、App等。数组在JavaScript中是常用的数据结构,所以用户的问题实际上是关于在UniApp环境下JavaScript数组的最长度限制。 接下来,我需要确认JavaScript本身的数组长度限制。根据ECMAScript标准,数组的索引是从0到2^32-1,也就是最长度是2^32-1,约是4294967294。不过实际应用中,这个长度会受到运行环境的内存限制,比如浏览器的可用内存或者移动设备的内存。如果数组过,可能导致内存不足,进而出现性能问题或崩溃。 然后,考虑UniApp的运行环境。UniApp编译到不同平台时,如微信小程序、H5或原生App,它们的JavaScript引擎可能不同。例如,微信小程序使用的是JavaScriptCore,而H5可能使用不同浏览器的V8引擎。不同引擎对内存的管理和限制可能有所差异,但通常来说,数组的理论最长度由JavaScript语言本身决定,实际受限于具体运行环境的内存。 还需要考虑实际开发中的情况。多数应用不会用到接近理论最长度的数组,因为处理这么数据会导致严重的性能问题,如页面卡顿、内存溢出等。开发者通常通过分页加载、懒加载或后端处理来优化数据量的场景。 此外,可能需要注意不同平台的具体限制。例如,某些小程序平台可能对内存使用有更严格的限制,导致实际可用的数组长度更小。因此,在UniApp中处理型数组时,需要测试目标平台的性能表现,并优化数据处理方式,比如使用虚拟列表、分块处理等技术。 总结起来,回答需要涵盖理论上的JavaScript数组长度限制,UniApp各平台的实际内存限制,以及实际开发中的优化建议。确保用户明白虽然理论上数组可以很,但实际应用中应避免处理过数据,采取合适的分页或懒加载策略。</think>UniApp作为基于JavaScript的跨平台框架,其数组长度受JavaScript语言规范及运行环境的共同限制。以下是逐步说明: 1. **JavaScript理论限制** - 根据ECMAScript标准,数组最索引值为`2^32 - 1`(即`4294967294`) - 代码验证: ```javascript let arr = new Array(4294967295) // 报错 RangeError: Invalid array length let arr = new Array(4294967294) // 创建成功(但需要足够内存) ``` 2. **实际运行环境限制** - **H5环境**:依赖浏览器内存(通常1GB左右),实际安全长度约`10^7`(千万级) - **小程序**:微信小程序单进程内存上限约`1GB`,数组元素过多会导致白屏 - **App平台**:iOS/Android内存更,但单个数组超过`5×10^7`元素仍可能崩溃 3. **UniApp开发建议** - 临界值测试(不同设备表现): ```javascript // 性能测试示例 let testArray = [] for(let i=0; i<1e7; i++){ // 1000万元素 testArray.push({id:i, data:Math.random()}) } // 在低端安卓机上可能出现明显卡顿 ``` - 优化方案: ✅ **分页加载**:每次请求`20-100`条数据 ✅ **虚拟列表**:使用`<scroll-view>`+动态渲染 ✅ **数据分片**:数据拆分为多个子数组 ✅ **Web Worker**:复杂运算放在后台线程 4. **典型场景处理** - 表格渲染:保持DOM节点数`<1000` - 本地缓存:单个`uni.setStorage`建议`<1MB` - 图片列表:使用懒加载组件`<image lazy-load>` **总结**:UniApp数组长度理论最值是`4294967294`,但实际安全值应控制在: - 内存敏感场景:`<10万`条 - 普通数据处理:`<50万`条 - 高性能设备:`<500万`条 建议使用`console.memory`监测内存使用: ```javascript setInterval(() => { console.log(performance.memory) // H5环境可用 }, 5000) ```
评论 12
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值