于常见的触底懒加载的优劣对比

优势:

  1. 滚动平滑性: 虚拟列表可以在滚动时实时渲染可见区域内的数据,保持滚动的平滑性,不会因为数据量大而导致滚动卡顿。
  2. 性能优化: 虚拟列表能够有效减少渲染的 DOM 元素数量,从而提高页面的性能和响应速度。
  3. 快速渲染: 虚拟列表根据滚动位置计算需要渲染的数据,渲染速度较快,可以更快地展示数据。

劣势:

  1. 不适用动态数据: 虚拟列表适用于静态数据或数据变化不频繁的情况,对于动态变化的数据需要额外的处理。

效果展示

elementUI虚拟列表activekeys 实现原理 vue虚拟表格_数据

 

 

创建一个父级div

elementUI虚拟列表activekeys 实现原理 vue虚拟表格_javascript_02

 

主要添加下面两个属性,其他样式随便

overflow: auto;
position: relative;

 

然后添加子级div仅用于撑开父级,高度是根据数据量来的,我这里模拟1w条数据 高度55w px 

elementUI虚拟列表activekeys 实现原理 vue虚拟表格_javascript_03

 

 然后再添加 存放数据的盒子 使用绝对定位

elementUI虚拟列表activekeys 实现原理 vue虚拟表格_html5_04

数据展示

elementUI虚拟列表activekeys 实现原理 vue虚拟表格_javascript_05

 

实现逻辑

滚动实际是撑开的div实现的,与数据展示没有关系,展示数据的box盒子 使用绝对定位和top 让它一直固定在能看到的位置

数据的展示:

        上图中可以看到,第一跳数据已经滚动到了顶部以外,当它超出一个行高的时候 它就会被删除替换成地二条数据 比如 开始是 0--9 当滑动的时候 他就变成了 1 -- 10 然后top下移一个行高。

        在下边我们看到除了能看到的22 在dom里面还有24 这个就是防止下滑太快导致出现空白区域的

 完整代码

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <style>
        .content{
            width: 500px;
            height: 550px;
            border: #2d9f75 1px solid;
            overflow: auto;
            margin: 0 auto;
            position: relative;
        }
        .item-box{
            position: absolute;
            width: 100%;
            top: 0; /* Add top: 0; */
            left: 0; /* Add left: 0; */
        }
        .item-li{
            width: 100%;
            text-align: center;
            height: 55px;
            line-height: 55px;
            border: antiquewhite 0.5px solid;
        }
    </style>
</head>
<body>

<div id="app">
    <div class="content" ref="contentRef" @scroll="handleScroll">
<!--        根据总条数和 每行的高度 计算出 高度,次div 只用于撑开父级 出现滚动条-->
        <div :style="{'height':`${total * this.lineHeight}px`}"></div>
<!--        用于绝对定位,展示可视窗口数据-->
        <div class="item-box">
            <div v-for="(item,index) in visibleList" :key="index" class="item-li">{{item.name}}</div>
        
        </div>
    
    </div>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script>
<script>
    var app = new Vue({
        el: '#app',
        data: {
            total:10000,// 总条数 ,也可根据list数组长度计算
            lineHeight:55,// 每一行高度
            bufferSize:2,// 缓冲数
            list:[],// 原数组
            visibleList: [],// for循环 展示的数组
        },
        methods:{
            updateVisibleList() {
                // 获取父级div dom计算距离顶部距离
                const content = this.$refs.contentRef; 
                // 获取浮动div 设置top值
                const itemBox = this.$el.querySelector('.item-box');
                // content.scrollTop 是当前滚动条距离顶部的距离 / this.lineHeight(每行高度) 得出可视窗口内 展示的数据开始下标
                const startIndex = Math.floor(content.scrollTop / this.lineHeight);
                /* content.clientHeight 可视窗口区域高度用于计算 窗口内展示多少行数据 ,
                 bufferSize缓冲数 在原数据上多显示两行 防止快速滑动的时候出现白色区域*/
                const endIndex = startIndex + Math.ceil(content.clientHeight / this.lineHeight) + this.bufferSize;
                // list 是1万条数据,visibleList才是正常for循环的数据,需要根据下标赋值
                this.visibleList = this.list.slice(startIndex, endIndex);
                // 设置绝对定位top 使得 itemBox 始终在我们的视线内
                itemBox.style.top = `${startIndex * this.lineHeight}px`;
            },
            handleScroll(){
                this.updateVisibleList();
            }
        },
        mounted(){
            // 构造1万条数据 一般来说是从后端请求的数据
            for (let i = 0; i < this.total;i++) {
                this.list.push({
                    name:'name'+i
                })
            }
            this.updateVisibleList();
        }
    })
</script>
</body>
</html>