解决加载大量列表DOM导致浏览器性能瓶颈的虚拟滚动技术_html dom节点100多个 加载起来浏览器卡顿如何解决

那么问题就来了,如何计算可视区域内需要渲染的元素,我们通过如下几步来实现虚拟滚动:

  • 每一行的高度需要相同,方便计算
  • 需要得知渲染的数据量(数组长度),可基于总量和每个元素的高度计算出容器整体的所需高度,这样就可以伪造一个真实的滚动条
  • 获取可视区域的高度
  • 在滚动事件触发后,滚动条的距顶距离也可以理解为这个数据量中的偏移量,再根据可视区域本身的高度,算出本次偏移的截止量,这样就得到了需要渲染的具体数据
  • 如果类似于渲染一个宽表,单行可横向拆分为多列,那么在X轴上同理实现一次,就可以横向的虚拟滚动

【背景说明】假设实际开发中服务端一次响应10万条列表数据,此时设备屏幕只允许容纳10条,那么用户理论上只可以看见10条数据。此时如果前端将10万条数据全部渲染成DOM元素,可能造成程序卡顿,占用较大资源,非常影响用户体验,那么虚拟滚动技术就完美的解决了这一问题。

【虚拟滚动案例网址】虚拟滚动原理(未来此地址可能失效,失效后请直接复制源码学习)

【虚拟滚动的实现】

<!DOCTYPE html>
<html>

<head>
    <meta charset="UTF-8">
    <!-- import CSS -->
    <link rel="stylesheet" href="https://unpkg.com/element-ui/lib/theme-chalk/index.css">
    <script src="https://cdn.bootcdn.net/ajax/libs/vue/2.6.13/vue.min.js"></script>
    <!-- import JavaScript -->
    <script src="https://unpkg.com/element-ui/lib/index.js"></script>
    <title>虚拟滚动原理</title>
</head>

<body>
    <div id="app">
        <el-row :gutter="10">
            <el-col :xs="6" :sm="6" :md="5" :lg="4" :xl="2">
                <el-button type="danger" @click="virtualScrolling(20)">20条</el-button>
            </el-col>
            <el-col :xs="6" :sm="6" :md="5" :lg="4" :xl="2">
                <el-button type="primary" @click="virtualScrolling(100)">一百条</el-button>
            </el-col>
            <el-col :xs="6" :sm="6" :md="5" :lg="4" :xl="2">
                <el-button type="success" @click="virtualScrolling(1000)">一千条</el-button>
            </el-col>
            <el-col :xs="6" :sm="6" :md="5" :lg="4" :xl="2">
                <el-button @click="virtualScrolling(100000)">十万条</el-button>
            </el-col>
        </el-row>
        <div class="wrap" @scroll="liScroll">
            <ul class="ul_wrap" :style="`height:${ulHei}px`">
                <li class="li_item" :style="`height:${liHei}px;transform:translateY(${ScroolNum}px)`"
                    v-for="item in liList" :key="item">
                    {{item}}
                </li>
            </ul>
        </div>
    </div>
</body>
<style>
    .wrap {
        height: 400px;
        background-color: #fff;
        overflow: scroll;
        margin-top: 20px;
    }

    .li_item {
        border: 1px red solid;
        line-height: 50px;

    }
</style>
<script>
    new Vue({
        el: '#app',
        data(){
            return {
                liHei: 50,//li的高度
                ulHei: 480,//ul的高度
                liList: [],//真实展示的列表
                scrollHei:0,//@scroll事件滚动的top值
                ScroolNum: 0,//scrollHei能被li高度取余数的整数值。ScroolNum=scrollHei-(scrollHei%liHei)
                showList: 0,//真实展示的条数
                tableData: [],//全部数据的集合
                lastTime:0,//最后时间
            }
        },
        mounted () {
            this.virtualScrolling(100)
            
        },
        methods: {
             /**滚动监听 */
            liScroll (e) {
                if(new Date().getTime()-this.lastTime>40){//设置时间间隔,防止滚动事件高频触发消耗内存资源
                this.ele = e;//保存元素,方便重置scrollTop值
                this.scrollHei = e.target.scrollTop;//保存滚动条scrollTop值
                this.ScroolNum = this.scrollHei - (this.scrollHei % this.l

**真题解析、进阶学习笔记、最新讲解视频、实战项目源码、学习路线大纲**
**详情关注公中号【编程进阶路】**

iHei);//获取已滚动到页面上方不可见的li元素的总高度(translateY的偏移高度)
                let len = this.ScroolNum / this.liHei;//计算已经有多少个li滚动到页面上方(视图上方用户不可见的数量)
                this.liList = this.tableData.slice(len, len + this.showList);//每次滚动事件后重新计算展示内容(截取的内容对应全部数据集的部分内容)
                this.lastTime=new Date().getTime();//记录最后一次更新时间
                }
                
            },
           /**初始化数据*/
            virtualScrolling (num) {
                let arr = [];//初始化数组
                for (let i = 0; i < num; i++) {//计算给定数据量
                    arr.push(i+1)
                }
                this.tableData = arr;//全部数据集
                this.showList = Math.floor(this.ulHei / this.liHei) + 4;//计算真实渲染的列表数量
                this.liList = this.tableData.slice(0, this.showList);//初始化可视列表的内容
                this.lastTime=new Date().getTime();//记录最后一次更新时间
                this.$message({
                    message: `当前数据为${num}条`,
                    type: 'success'
                    });
               
                if (!!this.ele) {//判断监听元素是否保存到ele字段中
                    this.ele.target.scrollTop = 0;//如果元素存在ele中则将scrollTop初始化为0;
                    this.ScroolNum=0;//初始化translateY的偏移高度
                }
               
            },
        }
    })
</script>

</html>

【实现原理】

1、获取滚动高度

2、列表单个item的高度

3、计算屏幕容纳几个item

4、计算滚动了几个item到顶部不可见区域

5、使用css3的transform属性将滚动到上方不可见区域的DOM元素偏移到可见区域,同时进行数据的更新(重绘操作节约性能)。

总结:虚拟滚动技术的实现是合理运用“回流必定发生重绘,而重绘不一定会引发回流”的理论进行实现。

读者福利

========

由于篇幅过长,就不展示所有面试题了,想要完整面试题目的朋友(另有小编自己整理的2024大厂高频面试题及答案附赠)


  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值