uniapp/vue虚拟列表,数据列表渲染优化

Posted Genting丶incubus

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了uniapp/vue虚拟列表,数据列表渲染优化相关的知识,希望对你有一定的参考价值。

引言

相信大家经常会遇到展示一堆数据的需求,几十条数据还好,要是几百上千条,甚至带上了图片。那就会卡得不行。这时候就需要按需加载

按需加载有懒加载虚拟列表

  • 懒加载:通过JS滚动或触底触发事件来加载更多的数据,类似分页。
  • 虚拟列表:只加载可视区域的数据,通过计算长度区间反推需要加载的数据来实现假滑动。

二者异同

很明显,懒加载虽然也有优化,可是当用户疯狂下拉刷新时候最后还是会卡,虽然很难有那种场景。懒加载的好处就是,用户往回刷时候因为加载过,所以看上面的内容会比较顺滑。

虚拟列表则是只加载可视范围的数据,需要精确计算,若不精确计算也可,但是有些数据会只显示了一部分(这个就需要个人自己优化一下计算的算法了,符合需求就可),而且因为是假滑动,所以观感有可能没有懒加载这么好。

两者在数据请求时,可以一次性拿完,也可分次拿取,懒加载便是下滑加载或触底时候请求新数据加到旧数据里。但虚拟列表拿的时候需要参考懒加载,因为用户也有往上滑的需求,这算法你们不想累死自己和后端吧。

接下来用Uniapp来演示,原生vue也可参考使用(更方便),理论上是一样的,区别就在于uniapp做微信小程序时候没有document可供使用(除非使用dhtml-weixin等插件),非H5端在某些组件上不能使用ref获取实例(如view),如此一来操作dom,只能通过官方提供的uni.createSelectorQuery()接口。

原理

 如图,黑框是数据列表的总高度,红框是你设定的可视范围,与动图里不同的是,红框内的数据是实时生成的(并不是通过隐藏其他数据),并且因为偏移量采用了取余操作(如果有需要可以自己定制),保证了在红框内第一条数据永远是完整展示的。只是因为滑动时未停下,js未响应前,新的列表不会生成,就会有一个假滑动的效果。

代码

<template>
	<scroll-view class="container" scroll-y="true" @scroll="scroll" >
		<!-- 虚拟列表总高度 -->
		<view :style="'height': `$totalHeightrpx`, 'position': 'relative'">
			<!-- 可视渲染区 -->
			<view :style="'top': `$toppx`" style="width: 100%;position:absolute">
                <!--在这里自定义你数据的展示结构和样式,itemHeight为这里的总高度-->
				<view  v-for="(item,index) in showList" :key="index" class="item">
					<span>我是第item.index条数据</span>
				</view>
			</view>
		</view>
	</scroll-view>
</template>

<script>
export default 
	data()
		return
			allList:[],//原始数据列表
			//虚拟列表
			showList: [],  //可视区域显示的数据
			itemHeight: 100,//每条数据所占高度
			showNum: 0,  //可视区域显示的最大条数
			top: 0, //偏移量
			scrollTop: 0,  //卷起的高度
			startIndex: 0,  //可视区域第一条数据的索引
			endIndex: 0,  //可视区域最后一条数据的索引+1,
		
	,
	onLoad() 
        //获取数据列表
		for(let i=0;i<100;i++)
			this.allList.push('index':i)
		
		// console.log(this.allList)
	,
	onShow() 
        //第一次时调用一下,且uni.createSelectorQuery()需要在生命周期mounted之后使用
		this.scroll()
	,
	computed: 
		totalHeight() 
			return this.allList.length*this.itemHeight*2//因为rpx和px的关系
		
	,
	methods:
	//虚拟列表
	getShowList()
        //可视区域能出现的数据条数
		this.showNum = Math.ceil(this.contentHeight/this.itemHeight);  
		// console.log('可视数量',this.showNum)

        //可视区域第一条数据的索引
		this.startIndex = Math.floor(this.scrollTop/this.itemHeight);   
		// console.log('初始索引',this.startIndex)

        //可视区域最后一条数据的下一条数据
		this.endIndex = this.startIndex + this.showNum;
   	
        //可视区数据,会比实际可视多渲染一条		
        this.showList = this.allList.slice(this.startIndex, this.endIndex)  
		// console.log(this.showList)

        //保证滑动时第一条数据完整展示
		let offsetY = this.scrollTop - (this.scrollTop % this.itemHeight);  

		this.top = offsetY;
	,
	scroll()
		// 利用uniapp提供的接口获取可视区域的高度和滚动高度
		let query=uni.createSelectorQuery()
		let container=query.select('.container');
		container.fields(
			// rect:true,   //是否返回节点布局位置信息left,top,right,bottom
			size:true,  //是否返回节点尺寸信息width,height
			scrollOffset:true //是否返回节点滚动信息scrollLeft,scrollTop
		,(res)=>
			console.log(res)
			this.scrollTop=res.scrollTop
			this.contentHeight=res.height
			this.getShowList();//因为所在函数是异步
		).exec()
	,
	

</script>

<style>
	.container
		width: 100%;
		height: 100vh;
        /*原生一定得有这个overflow的hidden效果,此处用了scroll-view所以不需要*/
		/*overflow:auto;*/
	
	
	.item
		/* 按照实际需求写css */
		width: 100%;
		height: 200rpx;/* 要对应上itemHeight */
		border: 1rpx solid slateblue;
	
</style>

注意点

1、uniapp里需要使用scroll-view才能实现隐藏滑动效果。原生的看代码里一样加上overflow:auto即可滑动,原生把所有view结构换成div。

2、uni.createSelectorQuery()的那个获取信息成功后执行的函数是异步执行的,所以需要留意一下你的同步操作,比如this.getShowList()不要放在外面。

3、可惜的是,不知道是不是v-for里的.item的问题,uni.createSelectorQuery()死活都拿不到节点,否则可以动态拿到每个数据节点的实际总高度。(注意这里不适用每条数据高度都不一样的情况,如需要高度不一样,请自行调整,如把itemHeight单独放在list的对象内之类,或通过改变现有结构统一固定每条数据的高度

所以我这里uniapp是写死了itemHeigh,itemHeigh(px单位制)和下面css样式里的height需要对应上,你也可以看到我computed里让itemHeigh乘了2,(因为大多数设备的rpx和px的css像素比例都是2:1)其实对应不上,效果还是会有的,所以不用特别纠结代码里的rpx和px单位。只要渲染的列表数据长度大于可视区域的列表数据长度即可。

先写到这了,有想起来或者出错再补充修改,如果你有更好的建议或纠错,欢迎评论,多多点赞谢谢。

React 虚拟化长列表

嗨,我是勾勾。



今天在整一个项目的时候,遇到一个长列表展示的优化问题。当时想的是进行数据分页,但是需要去和后台进行沟通。我的原则是尽量不麻烦别人,因此我搜索了一些方案,最后在 react 官方上获取到了解决方法——虚拟化列表。


虚拟化列表


我们来看下官方介绍。


“虚拟化列表是一项“虚拟滚动”技术。这项技术会在有限的时间内仅渲染有限的内容,并奇迹般地降低重新渲染组件消耗的时间,以及创建 DOM 节点的数量。”


看起来真的可以达到优化长列表的效果,按照流程我们试一试。


在 react 项目中使用虚拟化列表需要使用一项模块叫 react-virtualized。



虚拟化列表实现流程


为了快速实现虚拟化列表,前面的基础配置我就不说了,直接从使用这个虚拟化包开始。


首先,我们安装这个虚拟化包。

npm i react-virtualized


这个包对外暴漏了一些组件 api。这里我们使用的就是 List 组件。



我们简单看几个 <List width={} height={} rowHeight={}  rowRenderer={}></List>


  • width 这个 List 组件的宽度

  • height 这个 List 组件的高度

  • rowHeight 每一行的高度

  • rowRenderer 每一行渲染都要执行的函数


代码如下:


  
    
    
  
import React,{ Component,useState,useEffect,Fragment,Suspense} from "react"import {List} from 'react-virtualized';function getArr() { //模拟数据 let arr = [] for(var i=0;i<1000;i++){ arr.push({name:"zhangsan"+i}) } return arr}let arr = getArr()console.log(arr)function App() { return( <> <List  width={400}  height={200}  rowCount={arr.length}  rowHeight={40} rowRenderer={rowRenderer}/> </> )}function rowRenderer({key,index,style}) { return ( <div key={key} style={style}>{arr[index].name}</div> )}
export default App


在页面中,我们就能看到下面的形式。



在审查元素中,我们的代码中一直都会有这5个div出现,根据视图显示的内容,不会出现很多的 div。


推荐阅读:






点个“在看”和“”吧,

毕竟我是要成为前端网红的人。

以上是关于uniapp/vue虚拟列表,数据列表渲染优化的主要内容,如果未能解决你的问题,请参考以下文章

小程序长列表渲染优化另一种解决方案

React 虚拟化长列表

记录React性能优化之“虚拟滚动”技术——react-window

vue长列表性能优化

Vue或React的虚拟列表

虚拟滚动列表和css虚拟滚动有思考