前端性能优化----懒加载

54 阅读1分钟

懒加载定义

懒加载(延迟加载):仅在需要资源时才加载的策略

原理:用户滚动页面时,判断元素是否处于可视区域,而可视区域外的元素资源(如图片)不会加载。

场景:

  • 图片懒加载
  • 列表的无限滚动
  • 可点击链接的预加载

懒加载的方案

  • 监听scroll事件时判断元素当前相对视图的位置
  • 通过IntersectionObserver接口(提供一种异步观察目标元素与其祖先元素或顶级文档视窗交叉状态的方法)

懒加载原理:可视区域的判断实现

方法一:getBoundingClientRect

getBoundingClientRect()元素,返回值是一个DOMRect对象,有left、top、right、bottom、x、y、width和height属性,来说明元素在视图里面的相对位置

<html lang="en">

<head>
  <meta charset="UTF-8" />
  <title>Lazyload-getBoundingClientRect</title>
  <style>
    img {
      display: block;
      margin-bottom: 50px;
      height: 400px;
    }
  </style>
</head>

<body>
  <img src="" lazyload="true" data-src="assets/images/iu.jpeg" />
  <img src="" lazyload="true" data-src="assets/images/iu1.jpeg" />
     ...
  <img src="" lazyload="true" data-src="assets/images/iu3.jpeg" />
  <script>
    function checkElement(element) {
      const viewWidth = window.innerWidth || document.documentElement.clientWidth
      const viewHeight = window.innerHeight || document.documentElement.clientHeight
      const {
        top,
        right,
        bottom,
        left,
      } = element.getBoundingClientRect() || {}
      return (
        top >= 0 &&
        bottom <= viewHeight &&
        left >= 0 &&
        right <= viewWidth
      )
    }
    function lazyload() {
      var eles = document.querySelectorAll('img[data-src][lazyload]')
      Array.prototype.forEach.call(eles, function (el, index) {
        var rect
        if (el.dataset.src === "")
          return
        if (checkElement(el)) {
          !function () {
            var img = new Image()
            img.src = el.dataset.src
            img.onload = function () {
              el.src = img.src
            }
            el.removeAttribute("data-src")//移除属性,下次不再遍历
            el.removeAttribute("lazyload")
          }()
        }
      })
    }
    lazyload()//刚开始还没滚动屏幕时,要先触发一次函数,初始化首页的页面图片
    document.addEventListener("scroll", lazyload)
  </script>
</body>

</html>

方法二:通过IntersectionObserver接口

<script>
    function lazyload() {
      // IntersectionObserver的属性
      const options = { threshold: 1.0 }
      const intersectionObserver = new IntersectionObserver(function (entries, observer) {
        entries.forEach(entry => {
          console.log('entry', entry);
          const el = entry.target
          if (entry.isIntersecting) {
            !function () {
              var img = new Image()
              img.src = el.dataset.src
              img.onload = function () {
                el.src = img.src
              }
            }()
          }
        });
      }, options);
      // start observing
      var eles = document.querySelectorAll('img[data-src][lazyload]')
      Array.prototype.forEach.call(eles, function (el, index) {
        intersectionObserver.observe(el);
      })
    }
    lazyload()
  </script>