图片懒加载

前端 0 511 0
发表于: 2020-08-21 22:07:13

简介: 暂无~

图片懒加载

场景

一个网页会包含很多的图片,例如淘宝京东这些购物网站,商品图片很多,如果在首页就全部加载的话,会影响渲染速度(比如出现白屏)和浪费带宽,为了解决以上问题,提高用户体验,就出现了懒加载方式来减轻服务器的压力,优先加载可视区域的内容,其他部分等进入了可视区域再加载,从而提高性能。

原理

一张图片就是一个img标签,浏览器是否发起请求图片是根据img的src属性,所以实现懒加载的关键就是,在图片没有进入可视区域时,先不给img的src赋值,这样浏览器就不会发送请求了,等到图片进入可视区域再给src赋值。

实现

  1. 加载loading图片进行占位
  2. 判断哪些图片要加载
  3. 将loading图片替换真图片

html结构:

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Document</title>
  </head>
  <body>
    <img
      data-src="https://resource.hsslive.cn/image/1578937683585vueblog.webp"
      src="https://resource.hsslive.cn/image/f926bacffc39fc496f22ca13a68c3062.jpg"
      alt="加载中..."
      width="300"
      height="300" />
    <img
      data-src="https://resource.hsslive.cn/image/1582634581438regexr.webp"
      src="https://resource.hsslive.cn/image/f926bacffc39fc496f22ca13a68c3062.jpg"
      alt="加载中..."
      width="300"
      height="300" />
    <img
      data-src="https://resource.hsslive.cn/image/1582472959525git.webp"
      src="https://resource.hsslive.cn/image/f926bacffc39fc496f22ca13a68c3062.jpg"
      alt="加载中..."
      width="300"
      height="300" />
    <img
      data-src="https://resource.hsslive.cn/image/1582618699043array.webp"
      src="https://resource.hsslive.cn/image/f926bacffc39fc496f22ca13a68c3062.jpg"
      alt="加载中..."
      width="300"
      height="300" />
    <img
      data-src="https://resource.hsslive.cn/image/1638093406012author.webp"
      src="https://resource.hsslive.cn/image/f926bacffc39fc496f22ca13a68c3062.jpg"
      alt="加载中..."
      width="300"
      height="300" />
    <img
      data-src="https://resource.hsslive.cn/image/1662362144932__7TCL__sdd.png"
      src="https://resource.hsslive.cn/image/f926bacffc39fc496f22ca13a68c3062.jpg"
      alt="加载中..."
      width="300"
      height="300" />

  </body>
</html>

计算offsetTop实现

缺点:offsetTop是计算距离的父级的元素的值,不是计算相对屏幕的值!

console.log('计算offsetTop实现');

// 懒加载
function lazy() {
  // 获取页面滚动条卷去的高度
  let scrollTop = document.body.scrollTop || document.documentElement.scrollTop;
  // 获取页面高度
  let windowHeight =
    window.innerHeight || document.documentElement.clientHeight;
  // 获取所有img标签
  var imgs = document.querySelectorAll('img');

  for (let i = 0; i < imgs.length; i++) {
    // 获取每个img标签距离body的高度
    let imgOffsetTop = imgs[i].offsetTop;
    console.log(imgOffsetTop, scrollTop);
    /**
     * 1.如果img标签距离body的高度小于(页面高度+被卷去的高度),则代表当前img标签在可视区域,则加载图片
     * 2.由于如果从最底部加载的话,最开头的图片一定符合上面的条件,
     * 因此要判断img标签距离body的高度有没有大于滚动的高度,大于滚动高度了才加载图片
     */
    if (imgOffsetTop < windowHeight + scrollTop && imgOffsetTop >= scrollTop) {
      const imgSrc = imgs[i].getAttribute('data-src');
      // 如果有data-src属性,将它的值赋给src
      if (imgSrc) {
        imgs[i].src = imgSrc;
        // 赋值后data-src就没用了,移除掉它
        imgs[i].removeAttribute('data-src');
      }
    }
  }
}

// 刚进首页不触发滚动事件,因此要先加载一次
lazy();

// 监听滚动事件
window.addEventListener('scroll', lazy);

getBoundingClientRect实现

console.log('getBoundingClientRect实现');

// 懒加载
function lazy() {
  // 获取页面高度
  let windowHeight =
    window.innerHeight || document.documentElement.clientHeight;
  // 获取所有img标签
  var imgs = document.querySelectorAll('img');
  // 延迟加载图片
  for (let i = 0; i < imgs.length; i++) {
    // 获取每个img标签距离body的高度
    let top = imgs[i].getBoundingClientRect().top;
    /**
     * 如果图片相对屏幕的top值大于屏幕的高度,则代表没出现在屏幕
     */
    if (top > 0 && top <= windowHeight) {
      const imgSrc = imgs[i].getAttribute('data-src');
      // 如果有data-src属性,将它的值赋给src
      if (imgSrc) {
        imgs[i].src = imgSrc;
        // 赋值后data-src就没用了,移除掉它
        imgs[i].removeAttribute('data-src');
      }
    }
  }
}

// 刚进首页不触发滚动事件,因此要先加载一次
lazy();

// 监听滚动事件
window.addEventListener('scroll', lazy);

IntersectionObserver实现(推荐)

console.log('IntersectionObserver实现');
// 获取所有img标签
const imgs = document.querySelectorAll('img');
//监听回调
const callback = (entries) => {
  entries.forEach((item) => {
    // 是否相交
    if (item.isIntersecting) {
      const ele = item.target;
      const imgSrc = ele.getAttribute('data-src');
      if (imgSrc) {
        ele.src = imgSrc;
        // 加载过清空路径,避免重复加载
        ele.removeAttribute('data-src');
      }
    }
  });
};
const imgObserver = new IntersectionObserver(callback);
imgs.forEach((item) => {
  imgObserver.observe(item);
});

造轮子 JavaScript

最后更新于:2022-09-13 20:56:53

欢迎评论留言~
0/400
支持markdown
Comments | 0 条留言
按时间
按热度
目前还没有人留言~