• 性能优化之图片懒加载


    本文已参与「新人创作礼」活动,一起开启掘金创作之路

    为什么要懒加载

    图片资源体积影响加载请求,影响性能很严重
    花最少的时间,最大的优化

    1. 使用浏览器级别懒加载

    兼容性还行,还简单
    chrome 76以后出的
    可以实现懒加载效果

     "" lazy="loading" alt="">
    
    • 1

    背景图懒加载

    图片懒加载的关键在于获取元素的位置,
    并判断其是否出现在视口。故有以下三种方式

    滚动监听+scrollTop+offsetTop+innerHeight
    滚动监听+getBoundingClientRect()
    intersectionObserve()
    
    • 1
    • 2
    • 3

    IntersectionObserver

    ntersection Observer API
    可以异步监听目标元素与其祖先或视窗(viewport)交叉状态的手段。
    意思就是浏览器可以观察元素是否在可视区内。

    /*
      初始化 Intersectionobserver 类
      `callback`是当元素的可见性变化时候的回调函数,`options`是一些配置项
    */
    const observer = new IntersectionObserver(callback, options);
    /* 监听对应的 DOM 元素 */
    observer.observe(DOM);
    /* 取消对 DOM 元素的监听 */
    observer.unobserve(DOM);
    /*
      root:用于观察的根元素,默认是浏览器的视口
      rootMargin:用来缩放视窗的的大小,用法和 CSS 类似,
                  `10px 10px 30px 20px`表示top、right、bottom 和 left 扩大的对应值,
                  `10px 20px 5px`表示top,left&right, bottom 扩大的对应值
      thresholds: 当被监听的元素与根元素的交叉比例达到该值时触发回调函数,
                  默认为`[0]`, `0.1`表示当交叉比例达到`0.1`时触发回调,
                  `[0,0.5]`表示当交叉比例达到`0`和`0.5`时都会触发回调
    */
    const options = {
      root: null,
      rootMargin: 0,
      thresholds: 1,
    };
    /*
      回调函数在监听的 DOM 元素可见性变化时触发
      entries 中有多个参数,我们使用到以下两个参数
      isIntersecting 表示观察的元素是否出现在 root 元素可视区,
      intersectionRatio 表示观察的元素出现在 root 元素的比例
    */
    function callback(entries) {
      entries.forEach(entry => {
        if (entry?.isIntersecting || entry?.intersectionRatio > 0) {
          // 在此处进行图片地址替换
        }
      });
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36

    3. 使用 getBoundingClientRect

    当你的网站非常注重浏览器的兼容性时,以上的方法就无法满足你的需求,
    
    我们需要使用scroll及其他事件处理程序配合getBoundingClientRect来实现代码降级,
    
    从而确定确定元素是否位于视区中。此方法几乎可以兼容所以浏览器,
    
    但是性能不如intersectionObserve和loading=lazy
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    // 用于存当前页面已有的图片
    observerMap = new Map();
    // 通过滚动事件触发 scrollHandle 回调
    window.addEventListener('scroll', scrollHandle, true);
    // 每次回调里进行遍历已有图片列表
    function scrollHandle() {
      for (let dom of observerlist) {
        // 判断元素是否在可视区从而判断是否替换真实地址
      }
    }
    // 判断元素是否在可视区
    function checkDomInView(element) {
      const viewwidth = window.innerWidth || document.documentElement.clientWidth;
      const viewHeight = window.innerHeight || document.documentElement.clientHeight;
      const { top, right, bottom, left } = element.getBoundingClientRect();
      return left < viewwidth && right > 0 && top < viewHeight && bottom > 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    react实现分装