uniapp/vue 虚拟滚动列表(基础版)

4,496 阅读1分钟

基于老分享 云中桥 前端进阶 高性能渲染十万条数据(虚拟列表),改版了uniapp版的虚拟滚动列表,目前暂未对性能进行测试,只做了demo版,供大家参考。

  • 主要思路

    虚拟滚动列表在首屏加载时只加载可视化区域内需要显示的内容,在滚动时动态计算开始下标、结束下标,展示对应展示数据,始终保持较少的Dom数量。

  • 主要数据字段

    1. screenHeight 屏幕高度即可视区域高度
    2. startOffset 顶部偏移量
    3. startIndex 可视化区域的数据开始下标
    4. endIndex 可视化区域的数据结束下标
  • 具体实现

    1. 模板

    使用scroll-view 进行滚动区域设置,同时方便scroll获取滚动距离 scrollTop,视口高度为100vh。list-phantom:获取数据的总高度,展示竖向条,list内展示主要内容。

    <scroll-view ref='list' scroll-y="true" class='list-container' @scroll="handleScroll" style="height: 100vh;">
            <div class='list-phantom'  :style="{ height: listHeight + 'px' }"></div>
            <div class='list' :style="{ transform: getTransform }">
                <div v-for="(item,index) in visibleData" class='list-item' :key='item.id' :style="{height:itemSize+'px',lineHeight:itemSize+'px'}">
                                    {{item.value}}
                            </div>
                    </div>
    </scroll-view>
    

    2. 模板首先获取屏幕高度,计算展示屏幕可视化区域数量,同时计算总高度
        // 获取屏幕高度
        getScreenHeight(){
               const _this=this
               uni.getSystemInfo({
                       success: function (res) {
                                 _this.screenHeight=res.screenHeight
                               }
                       });
              },
    
         // 可显示的列表项数(itemSize为props传入的项目高度) 总高度
       	computed:{
            //可显示的列表项数
            visibleCount(){
                    return Math.ceil(this.screenHeight / this.itemSize)
            },	
            //列表总高度
            listHeight(){
                    return this.listData.length * this.itemSize;
            },
            //偏移量对应的style
             getTransform(){
                    return `translate3d(0,${this.startOffset}px,0)`;
            },	
            //获取真实显示列表数据
             visibleData(){
    	 return this.listData.slice(this.startIndex, Math.min(this.endIndex,this.listData.length));
    	  }	
        }
    
         // 计算可视化区域要展示的数据的开始与结束索引
           mounted() {
    		this.getScreenHeight()
    		this.startIndex = 0;
    		this.endIndex = this.startIndex + this.visibleCount;
            },
    

    3. 滚动时根据scrollTop计算开始与结束索引以及顶部偏移量
         handleScroll(e){
    	//当前滚动位置
    	let scrollTop = e.detail.scrollTop;
    	//开始索引
    	this.startIndex = Math.floor(scrollTop / this.itemSize);	 
    	//结束索引
    	this.endIndex = this.startIndex + this.visibleCount;
    	//顶部偏移量
    	this.startOffset = scrollTop - (scrollTop % this.itemSize);
         }      
    

    4. 设置顶部偏移量
        <div class='list' :style="{ transform: getTransform }"></div>
        computed:{
                //偏移量对应的style
                 getTransform(){
                        return `translate3d(0,${this.startOffset}px,0)`;
                      }
         },	
    

    demo模板地址