长列表渲染优化

21 篇文章 3 订阅
为什么要使用虚拟列表?

当数据量很大的时候,像有10万条数据的时候,我们一次性获得所有数据是不可能的,当然我们也可以使用分页的效果,但是这样用户的体验就不好了,用户喜欢往下滑动获得数据展示。当时当我们根据滑动获取数据的时候就会遇到另一个问题,不停的加载数据,导致页面堆积的节点越来越多,内存不断的增加,最后连滚动都出现了卡顿。所以虚拟列表蕴蓄而生

什么是进程?

进程是系统进行资源分配和调度的一个独立单位,一个进程内包含多个线程。

什么是虚拟列表?

虚拟列表也没有什么特别的地方,就是在页面上创建一个容器作为可视区,在这个可视区内展示长列表中的一部分,也就是在可视区域内渲染列表。
在这里插入图片描述
一个简单的可视区域模型,大概有五点需要说一下:

  • 可视区域大小
  • 真实列表大小
  • startIndex
  • endIndex
可视区域

就是这个盒子的高度

真实列表

真实列表就是被渲染出来的列表,举个例子:现在总数据有1000个,当实际上页面需要被渲染的列表数量只有100个*(就是可视区域内的数量),这 100 个 数据 就是真实列表。

<div @scroll="listScroll">
	<div class="list-body">	
	</div>
</div>
// style
 .list-body{
  position:absolute;
}

这里建议真实列表的长度需要比可视区域的高度长一点,这样有一个滚动条的话,之后可以通过scroll监听操作,这里说一下为什么用 绝对定位。
当一个元素频繁发生改变的时候,最好将这个模块通过绝对定位的方式,脱离文档流,这样可以减少重绘带来的影响。

浏览器渲染机制
  • 解析html,生成DOM树,解析css,生成cssDOM树
  • DOM树和CSSDOM树结合,生成渲染树(render tree)
  • 回流:根据生成的渲染树,进行回流,得到节点的几何信息(位置,大小)
  • 重绘:根据渲染树以及回流得到的几何信息,得到节点的绝对像素。
  • 将像素发送到GPU,展示在页面上。

脱离文档流之后,元素发生改变只会对这一部分进行重绘。

startIndex

被渲染的第一个元素的index就是片段中的第一个元素在总列表的位置,也就是数组中的index。
例如:总列表长度 1000 , 渲染片段为 100 - 200 , index就是 99

endindex

endindex就是 199 的位置。

虚拟列表的实现
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <style>
      .viewport {
         overflow-y: scroll;
         position: relative;
      }
	.scroll-list {
	  position: absolute;
	  top: 0;
	  left: 0;
	  width: 100%;
	  height: 100%;
	}
</style>
</head>
<body>
<ul id="app">
<!-- 能滚动的盒子 -->
  <div class="viewport" ref="viewport" @scroll="handlScroll">
    <!-- 滚动条 -->
    <div class="scroll-bar" ref="scrollbar"></div>
    <!-- 列表位置 -->
    <div class="scroll-list" :style="{transform:`translate3d(0,${offset}px,0)`}">
      <div v-for="item in visibleData" ref="items" :key="item.id" :vid="item.id">
        <!-- 通过插槽传出去 -->
        <slot :item="item"></slot>
      </div>
    </div>
  </div>
</ul>
<script src="../../js/vue.js"></script>
<script>
    new Vue({
        el: '#app',
        data(){
            return {
                list: [],//超长的显示数据
                itemHeight: 30,//每一列的高度
                showNum: 10,//显示几条数据
                start: 0,//滚动过程显示的开始索引
                end: 10,//滚动过程显示的结束索引
            }
        },
        computed: {
            //显示的数组,用计算属性计算
		    visibleData() {
		      let start = this.start - this.prevCount;
		      let end = this.end + this.nextCount;
		      return this.items.slice(start, end);
		    },
		      //前面预留几个 为了放置空白现象
		    prevCount() {
		      return Math.min(this.start, this.showNum);
		    },
		    //后面预留几个
		    nextCount() {
		      return Math.min(this.showNum, this.items.length - this.end);
		    },
        },
        mounted(){
            //构造一个超长列表
            for (let i = 0; i < 1000000; i++) {
                this.list.push('列表' + i)
            }
             //当前的一项高度*显示的项目高度
			this.$refs.viewport.style.height = this.size * this.remain + "px";
			//当前总长度*当前的项目高度
			this.$refs.scrollbar.style.height = this.items.length * this.size + "px"; 
        },
        methods: {
            scrollListener(){
                //获取滚动高度
                let scrollTop = this.$refs.listWrap.scrollTop;
                //开始的数组索引
                this.start = Math.floor(scrollTop / this.itemHeight);
                //结束索引
                this.end = this.start + this.showNum;
                //绝对定位对相对定位的偏移量
                this.$refs.list.style.top = this.start * this.itemHeight + 'px';
            }
        }
    })
</script>
</body>
</html>

看这个吧
手动代码分页
   var dqPage = $("#dqPage").text();//得到当前页数
            dqPage = parseInt(dqPage);//得到的文本转成int
            var pageCount = $("#pageCount").text();//得到总页数
            pageCount = parseInt(pageCount);
            var i = 1;
            i = parseInt(i);
            var item="";
            var href = "这里是请求地址";
            if (pageCount <= 5 ) {//总页数小于五页,则加载所有页
                
                for (i; i <= pageCount; i++) {
                    if (i == dqPage) {
                        item += "<span class='disabled'>"+i+"</span>"; 
                    }else{
                        item += "<a href='"+href+i+"' >"+i+"</a>"; 
                    }
                };
                $('#pageBtn').append(item);
                return;
            }else if (pageCount > 5) {//总页数大于五页,则加载五页
                if (dqPage < 5) {//当前页小于5,加载1-5页
                    for (i; i <= 5; i++) {
                        if (i == dqPage) {
                            item += "<span class='disabled'>"+i+"</span>"; 
                        }else{
                            item += "<a href='"+href+i+"' >"+i+"</a>"; 
                        }
                    };
                    if (dqPage <= pageCount-2) {//最后一页追加“...”代表省略的页
                        item += "<span> . . . </span>";
                    }
                    $('#pageBtn').append(item);
                    return;
                }else if (dqPage >= 5) {//当前页大于5页
                    for (i; i <= 2; i++) {//1,2页码始终显示
                        item += "<a href='"+href+i+"' >"+i+"</a>"; 
                    }
                    item += "<span> . . . </span>";//2页码后面用...代替部分未显示的页码
                    if (dqPage+1 == pageCount) {//当前页+1等于总页码
                        for(i = dqPage-1; i <= pageCount; i++){//“...”后面跟三个页码当前页居中显示
                            if (i == dqPage) {
                                item += "<span class='disabled'>"+i+"</span>"; 
                            }else{
                                item += "<a href='"+href+i+"' >"+i+"</a>"; 
                            }
                        }
                    }else if (dqPage == pageCount) {//当前页数等于总页数则是最后一页页码显示在最后
                        for(i = dqPage-2; i <= pageCount; i++){//...后面跟三个页码当前页居中显示
                            if (i == dqPage) {
                                item += "<span class='disabled'>"+i+"</span>"; 
                            }else{
                                item += "<a href='"+href+i+"' >"+i+"</a>"; 
                            }
                        }
                    }else{//当前页小于总页数,则最后一页后面跟...
                        for(i = dqPage-1; i <= dqPage+1; i++){//dqPage+1页后面...
                            if (i == dqPage) {
                                item += "<span class='disabled'>"+i+"</span>"; 
                            }else{
                                item += "<a href='"+href+i+"' >"+i+"</a>"; 
                            }
                        }
                        item += "<span> . . . </span>";
                    }
                    $('#pageBtn').append(item);
                    return;
                }
            }
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: 微信小程序中,可以使用 `scroll-view` 组件来展示列表,并使用 `wx:for` 指令来渲染列表数据。具体步骤如下: 1. 在 `wxml` 文件中,使用 `scroll-view` 组件包裹需要展示的列表内容,如下所示: ```html <scroll-view scroll-y="true"> <!-- 使用 wx:for 渲染列表数据 --> <view wx:for="{{list}}" wx:key="index">{{item}}</view> </scroll-view> ``` 2. 在对应的 `js` 文件中,定义列表数据并传递给 `wxml` 文件,如下所示: ```javascript Page({ data: { list: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] } }) ``` 其中,`list` 数组中的每个元素都会通过 `wx:for` 指令渲染为一个 `view` 组件。 3. 在 `scroll-view` 组件中,设置 `scroll-y` 属性为 `true`,即可开启纵向滚动。 需要注意的是,当列表数据较多时,可能会影响小程序性能,此时可以考虑使用分页加载等优化策略。 ### 回答2: 微信小程序是一种轻量级的应用程序,在小程序框架中,列表渲染是一个常见的需求。由于小程序的页面渲染机制是异步的,无法一次性将大量的数据全部渲染到页面上。因此,对于大数据量的列表渲染,我们可以采用分页加载或虚拟列表技术。 一种常见的列表渲染方式是分页加载。我们可以将数据分割成若干页,每次只加载当前页的部分数据,当用户滚动到页面底部时,再加载下一页数据。这种方式在渲染大数据量时可以提高性能,并减少用户等待时间。 另一种常见的列表渲染方式是虚拟列表。虚拟列表是一种只渲染可见区域的数据项的技术。当用户滚动列表时,只渲染当前可见区域的数据项,而不渲染所有数据。这种方式可以减少页面渲染的时间和内存的占用,提高性能和用户体验。 为了实现列表渲染,我们可以使用小程序框架提供的组件或第三方库。例如,使用官方组件"scroll-view"可以实现分页加载和虚拟列表。我们可以设置上拉触底事件,当用户滚动到页面底部时,触发加载下一页的数据;同时,在"scroll-view"中设置合适的高度和样式,来展示可见区域的数据项。此外,也可以使用第三方库如vant等来实现列表渲染。 总的来说,微信小程序的列表渲染可以通过分页加载或虚拟列表来实现,提高性能和用户体验。我们可以根据具体需求选择合适的方法,并利用小程序框架提供的组件或第三方库来简化开发过程。 ### 回答3: 微信小程序中的列表渲染通常使用的是WXML和WXSS来实现。在WXML中,我们可以使用<scroll-view>组件来实现列表的滚动效果。<scroll-view>组件具有scroll-view 和 scroll-y属性,通过设置scroll-y为true,可以实现竖向滚动。此外,我们还可以使用<view>组件来包裹列表中的每一项,使用wx:for循环语法来遍历数据源,并在每一项中显示对应的数据。 在WXSS中,我们可以设置<scroll-view>组件的高度、宽度以及滚动条的样式等。使用WXSS可以对列表项进行样式设置,如设置字体颜色、背景色等。 在数据量较大的情况下,为了提高列表渲染的性能,我们可以使用<block>组件对列表进行分块渲染。将一个列表分成多个块,通过分批加载,可以避免一次性渲染大量数据导致卡顿的情况发生。 此外,我们还可以使用小程序提供的scroll-into-view方法来实现对指定列表项的定位和滚动。 为了更好的用户体验,还可以在列表中添加上拉刷新和下拉加载更多的功能,这样用户可以在页面滚动到底部时自动加载更多数据,或者下拉列表时刷新数据,提高用户的浏览体验。 综上所述,微信小程序中的列表渲染主要通过scroll-view组件、wx:for循环语法、scroll-into-view方法以及上拉刷新和下拉加载等功能来实现。这些方法可以提高列表渲染的性能和用户体验,使用户能够流畅地浏览和操作列表数据。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值