性能优化:虚拟列表,如何渲染10万条数据的dom,页面同时不卡顿

Posted songbw

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了性能优化:虚拟列表,如何渲染10万条数据的dom,页面同时不卡顿相关的知识,希望对你有一定的参考价值。

最近做的一个需求,当列表大概有2万条数据,又不让做成分页,如果页面直接渲染2万条数据,在一些低配电脑上可能会照成页面卡死,基于这个需求,我们来手写一个虚拟列表

思路

  1. 列表中固定只显示少量的数据,比如60条
  2. 在列表滚动的时候不断的去插入删除dom
  3. startIndex、endIndex,不断的改变这个值来获取最新的显示列表
  4. paddingTop、paddingBottom撑开容器的滚动区域

首先看一下当直接插入2万条列表时,页面的性能
技术图片
可以看到火焰图中已经有了红色的部分了,dom渲染也耗时也有1s多

再来看一下当使用虚拟列表时页面的性能
技术图片
从火焰图中可以看出,火焰图中一篇绿油油的,这就证明,通过虚拟列表来进行渲染使页面性能得到了极大的提升

简单的虚拟列表demo实现

我们假设有一个容器,高度为600px,列表项每个高度为30px,那么根据列表的length我们就可以计算出滚动容器的总高度,也可以知道显示60条数据的高度,我们此时可以给容器加一个paddingBottom,来撑开容器,来模拟页面应该滚动的高度

this.paddingBottom = this.allHeight - this.scrollList.length * 30

容器同时还需要paddingTop用做当容器滚动顶部数据移除后撑起scrollTop

最后我们需要监听容器的滚动事件来不断的修改paddingTop、paddingBottom、startIndex、endIndex

最终效果
技术图片

最后附上所有代码

<!doctype html>
<html lang="zh">
<head>
    <meta charset="UTF-8">
    <meta name="viewport"
          content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
    <style>
        .container 
            width: 300px;
            height: 600px;
            overflow: auto;
            border: 1px solid;
            margin: 100px auto;
        
        .item 
            height: 29px;
            line-height: 30px;
            border-bottom: 1px solid #aaa;
            padding-left: 20px;
        
    </style>
</head>
<body>
<div id="app">
    <button @click="add">增加</button>
    <div class="container" ref="container">
        <div class="scroll-wrapper" :style="style">
            <div v-for="(item, index) in scrollList" :key="index" class="item">item</div>
        </div>
    </div>
</div>
<script src="./vue.js"></script>
<script>
    new Vue(
        el: '#app',
        data: 
            list: [
                '测试数据'
            ],
            startIndex: 0,
            endIndex: 60,
            paddingTop: 0,
            paddingBottom: 0,
            allHeight: 0
        ,
        computed: 
            scrollList() 
                return this.list.slice(this.startIndex, this.endIndex)
            ,
            style() 
                return 
                    paddingTop: this.paddingTop + 'px',
                    paddingBottom: this.paddingBottom + 'px'
                
            
        ,
        watch: 
            list(val) 
                const valLen = val.length
                this.allHeight = valLen * 30
                this.paddingBottom = this.allHeight - this.scrollList.length * 30
            
        ,
        mounted() 
            const container = this.$refs.container
            container.addEventListener('scroll', () => 
                const top = container.scrollTop
                this.startIndex = Math.floor(top / 30)
                this.endIndex = this.startIndex + 60

                this.paddingTop = top
                if (this.endIndex >= this.list.length - 1) 
                    this.paddingBottom = 0
                    return
                
                this.paddingBottom = this.allHeight - 600 - top
            )
        ,
        methods: 
            add() 
                let arr = new Array(50000).fill(0)
                arr = arr.map((item, index) => 
                    return index
                )
                this.list = [
                    ...this.list,
                    ...arr
                ]
            
        
    )
</script>
</body>
</html>

以上是关于性能优化:虚拟列表,如何渲染10万条数据的dom,页面同时不卡顿的主要内容,如果未能解决你的问题,请参考以下文章

vue长列表性能优化

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

前端性能优化分析

React组件性能优化

虚拟滚动技术 --- 解决加载大量列表DOM导致页面卡顿

React组件性能优化