长列表渲染中的虚拟列表处理

无论是在真实的项目开发中,还是面试的问题中,对前端的优化处理方式都十分看重,而面对真实的长列表,面对成千上万的数据列表,要怎么去渲染呢?

首先最常规的就是前,后端进行约定分页处理。假如有1000条数据,前端在利用ajax发送一些必要数据后,需要在加上总页数,和当前页数,那么此时,如果约定是10页的话,那么现在前端只是获取的当页的10条数据。跳转不同页面之后,获取不同页面的10条数据。这是最简单一种处理方式,不过这种方式也有它明显的弊端,假如要跨页寻找数据时候,就需要开辟新的存储空间去存,在实际情况中,甚至存在不能分页的情况,这时候要怎么进行优化呢?

先引入一种时间切片的方式,

时间切片的核心思想是:如果存在一个长任务不能在50毫秒内执行完(10万条数据的加载渲染),那么为了不阻塞主线程,这个任务应该让出主线程的控制权,使浏览器可以处理其他任务。让出控制权意味着停止执行当前任务,让浏览器去执行其他任务,随后再回来继续执行没有执行完的任务。

//需要插入的容器
let ul = document.getElementById('container');
// 插入十万条数据
let total = 100000;
// 一次插入 20 条
let once = 20;
//总页数
let page = total/once
//每条记录的索引
let index = 0;
//循环加载数据
function loop(curTotal,curIndex){
    if(curTotal <= 0){
        return false;
    }
    //每页多少条
    let pageCount = Math.min(curTotal , once);
    setTimeout(()=>{
        for(let i = 0; i < pageCount; i++){
            let li = document.createElement('li');
            li.innerText = curIndex + i + ' : ' + ~~(Math.random() * total)
            ul.appendChild(li)
        }
        loop(curTotal - pageCount,curIndex + pageCount)
    },0)
}
loop(total,index);

如上述代码所示,我们一次利用setTimeout加载20条,每次setTimeout是一次宏任务,在浏览器的执行机制中,没进行一轮的宏任务之后会进行渲染,这样的话,就可以实现,每加载20条数据后渲染,不会造成主线程一直被占用的情况。

第二种方式是虚拟列表

这种方法的核心思想就是,现将所有的数据得到,但是只去渲染视窗可见部分的数据。话不多说,上图

这一共有1000条数据,我们一次只渲染其中可见的10条。如图现在显示0 - 9, 随着滚轮往下移动,我们去渲染当时屏幕可以看见的那10条数据。也就是说同一个时间内也只是显示10条数据从而减少了对dom的操作,优化了性能。

来分析一下代码


<!DOCTYPE html>
<html>
<head lang="en">
    <meta charset="UTF-8">
    <title></title>
    <style type="text/css" rel="stylesheet">
    //分析css部分
        .content{
          background-color: orangered;
          overflow:auto;
          //这里是为了出现滚轮
          width: 50vw;
          height: 500px;
          //一条数据50px高,可视窗口500px,一页可以放10条数据
          margin-left: 25vw;
        }
        .target{
          height: 50000px;
          //整个滑轮可以滚动的长短也就是可以存储1000条数据
          box-sizing: border-box;
          //这里需要调整一下盒子模型,后续要配合padding-top属性设置偏移量。
        }
    </style>
</head>
<body>
<div class="content" >
    <!-- div标签是可视窗口 -->
    <ul class ="target">
    <!-- ul标签是滑动总长度 -->
    <!-- li标签放入其中,用于存放单挑数据 -->
    </ul>
</div>
</body>

 

<script>
  let datalength = 10;
  //每页显示数据
  let data = [];
  //总共的1000条数据,数组存放
  let showdata = [];
  //要去渲染的10条数据,数组存放
  let topdistance = 0;
  //记录偏移量
  let first;
  //首条数据的索引
  let end;
  //尾条数据索引
  for(let i = 0;i<1000;i++){
    data.push(i);
  }
  let div = document.querySelector('.content');
  let ul =  document.querySelector('ul');
  myscroll()
  //首屏渲染数据
  div.onscroll =  myscroll
  function myscroll(e){
    ul.innerHTML = '';
    //每次渲染之前清空内容
    topdistance = e?e.target.scrollTop:0;
    //手动设置偏移量
    ul.style.paddingTop =  topdistance+'px';
    //将偏移量赋值给paddingTop,注意上述css盒模型如果不设置一下的话,会导致滚轮一直下滑,ul的高度会被无限拉长
    let index = Math.floor(topdistance/50);
    //根据偏移量判断该从哪里截取
    first = index;
    end =index+datalength;
    showdata = data.slice(first,end);
    //对原生数据进行截取
    const dom = document.createDocumentFragment();
    let li = null;
    //下面操作dom节点进行渲染
    showdata.map((item)=>{ 
       li = document.createElement('li');
       li.style.height = '50px';
       li.innerHTML = item;
       dom.appendChild(li);
    })
    ul.appendChild(dom);
 }
</script>
</html>

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值