美文网首页
前端性能优化-处理大批量DOM元素

前端性能优化-处理大批量DOM元素

作者: 野蛮生长_ed2e | 来源:发表于2019-11-21 11:31 被阅读0次

    一次性在dom添加多个节点会产生很大的性能问题, 一次性加载多个dom元素的时候 页面会出现首次加载缓慢或者浏览器直接崩溃掉,介绍两种方法去优化

    1、分时函数

    <script type="text/javascript">
    
        function createDom(data) {
          const div = document.createElement('div');
          div.innerHTML = data;
          document.body.appendChild(div);
        }  
    
        function chunkData (data, num, callback) {
        
        let time; 
        const start = function() { 
          for (let i = 0; i < Math.min(num, data.length); i++) {
            callback(data.shift());
          }
        }
        
        return function () {
          time = setInterval(function () {
            if(data.length === 0) {
              
              return clearInterval(time);
            }
            start();
          } , 300);
        }
        
      }
        window.onload = function () {
          const data = [];//要加载的数据
          for(var i = 0; i <= 10000; i++) {
            data.push(i);
          }
         for(let i = 0; i < data.length; i++) { //1.简单粗暴的方法
            createDom(i);
          }
        // chunkData(data, 20, createDom)();//2.分时加载
        }
      
        </script> 
    

    下图一次性加载多个dom导致页面加载时间变长


    一次性插入多个dom页面渲染卡顿

    采用分时加载后(使用chunkData方法)

    分时加载
    判断渲染速度是否加快可以判断当发生 DOMContentLoaded 事件后,就会生成渲染树,生成渲染树就可以进行渲染了,这一过程更大程度上和硬件有关系了。

    2、虚拟列表

    虚拟列表的实现原理就是只渲染固定屏幕高度的几条数据 每次改变dom元素内容 模拟滚动 尽量不要去用插入dom并且删除dom这样的方式去优化 插入删除dom会造成浏览器的开销 引起浏览器回流

    • visibleCount 为计算可视区域的渲染条数
    • listHeight 为列表的总高度 用于撑开整个可视区域 用于滑动
    • startIndexendIndex 用于截取渲染数据
    componentDidMount() {
          const { data } = this.state; // 获取的全部数据
          this.startIndex = 0 
          this.listHeight = data.length * this.itemSize;
          this.visibleCount = Math.ceil(500 / this.itemSize) // 500是可视区的高度  
          this.endIndex = this.visibleCount   
    
          this.setState({ visibleData: data.slice(0,this.visibleCount) });
          
        }
    

    滚动监听事件

    this.startOffset 的作用是用于定位可视区域的数据,因为滑动会将可视区域的列表向上滑动 所以我们要计算整块的高度 例如第2个元素要替换第1个元素的时刻 我们将列表向下定位一个块的高度 这时候第一个元素就正好显示在屏幕的第一个位置 否则第一个元素就会滑上去了 scrolltop减去this.scrollTop % this.itemSize是因为我们要制造滑动效果 不能在第一个元素滑上去的距离小于一整块高度的时候去调整他的top 这样就不会有滑动效果了

    
    .wrapper {
      margin-top: 100px;
      border: 1px solid red;
     height: 500px;
      overflow: scroll;
      position: relative;
      -webkit-overflow-scrolling: touch;
    }
    .item {
      height: 50px;
      border: 1px solid darkcyan;
    
    }
    
    .phantom {
      position: absolute;
      left: 0;
      top: 0;
      right: 0;
      z-index: -1;
    }
    
    .list {
      left: 0;
      right: 0;
      top: 0;
      position: absolute;
      text-align: center;
    }
    
    onScrollList = (val) => {
          const { data } = this.state;
    
          this.startIndex =  Math.floor(this.refs.lala.scrollTop / this.itemSize);
          this.endIndex = this.startIndex + this.visibleCount;
          this.scrollTop = this.refs.lala.scrollTop;
          this.startOffset = this.scrollTop - (this.scrollTop % this.itemSize);
          this.setState({ visibleData: data.slice(this.startIndex, Math.min(this.endIndex, data.length)) });
          
        }
    
    render () {
          const { visibleData } = this.state;
          
          return (
            <div className='wrapper' ref={'lala'} onScroll={this.onScrollList}>
                <div className='phantom' style={{ height: this.listHeight + 'px' }}></div>
                <div className='list' style={{ top: this.startOffset + 'px' }}>
                {
                  visibleData.map((item) => <div className='item'>{item}</div>)
                }
                </div>
                
            </div>
          )
        }
    
    优化前页面卡住空白 渲染后性能绿油油👏🏻

    相关文章

      网友评论

          本文标题:前端性能优化-处理大批量DOM元素

          本文链接:https://www.haomeiwen.com/subject/ssgzictx.html