实现图片懒加载的两种方案

发布于 2023-12-11 10:57:18 字数 5186 浏览 20 评论 0

常见的懒加载方案

这个方案是借助滚动距离来判断的,获取 document.documentElement 的 scrollTop 与需要懒加载的图片标签的 offsetTop 进行比较,看图片是否进入可视区域,从而实现图片加载。

代码如下:

// 封装一个获取图片到顶部的距离
function getTop(elm){
  let tempTop = elm.offsetTop;
  //如果包裹 img 的父元素离顶部也有距离,那么也要把它加上
  while(elm = elm.offsetParent) { //注意这儿 offsetParent 返回的是元素不是数值,同时这儿是赋值语句
    tempTop += elm.offsetTop;
  }
  return tempTop;
}

function lazyLoad(imgs){
  //获取可视区域高度
  let viewHeight = document.documentElement.clientHeight || window.innerHeight;
  //获取滚动高度
  let scrollTopVal = document.documentElement.scrollTop || document.body.scrollTop;
  for(var i = 0; i < imgs.length; i++){
      if((viewHeight + scrollTopVal) > getTop(imgs[i])){
        imgs[i].src = imgs[i].getAttribute('data-src')
      }
  }
}

// 使用
// 给你需要懒加载的图片设置一个类名'lazy-load'
let imgs = document.querySelectorAll('.lazy-load');
lazyLoad(imgs);
// 进行滚动监听
window.onscroll = function() {
  lazyLoad(imgList);
}

使用交叉观察者实现懒加载

浏览器自带的 API IntersectionObserver 进行检测,十分方便

先贴上代码实现:

// 给你需要懒加载的图片设置一个类名'lazy-load'
let imgs = document.querySelectorAll('.lazy-load');

// 实例化一个交叉观察者对象
let obsever = new IntersectionObserver((entries) => {
  entries.forEach((item, index, arrSelf) => {
    // 判断检测的对象是否进入可视窗口
    if(item.isIntersecting) {
      // 进入后进行图片地址赋值
      item.target.src = item.target.dataset.src;
      // 实现图片加载后不在进行检测
      obsever.unobserve(item.target);
    }
  });
});

// 注册观察需要懒加载的 img
imgs.forEach((item) => {
  obsever.observe(item);
});

IntersectionObserver

用法

new IntersectionObserver(callback, options);
  • callback 是一个回调函数,接受一个参数,返回当前已监听并且发生了交叉的目标集合。
  • options 配置参数,可选,是一个对象。
new IntersectionObserver((entries) => {

}, {
  // options 参数
});

entries 当前已监听并且发生了交叉的目标集合,我们可以把它用来循环,参数表对于 entries 这个集合里面的每个对象都有如下常用的参数:

entries 下的对象

属性说明
boundingClientReact元素的空间信息,就是位置信息这些个
intersctionRatio元素可见区域的占比
isInterscting判断元素是否交叉,也就是元素在可视区是否可见了
target目标节点,跟我们使用事件的 event.target 效果一样

options 一个配置对象

属性说明
root指定父元素,默认为视窗
rootMargin触发交叉的偏移值,默认为 0px 0px 0px 0px。(上左下右,正数为向外扩散,负数则向内收缩)

IntersectionObserver 的实例对象的常用方法

名称说明参数
observe开始监听一个目标元素DOM 节点
unobserve停止监听一个目标元素DOM 节点
takeRecords返回所有监听的目标元素集合 
disconnect停止监听所有元素 

封装一个支持多浏览器的懒加载方案

IntersectionObserve 这个 API 用起来确实方便,但是还是有一部分浏览器不支持,所以需要封装判断下。

function getTop(elm){
  let tempTop = elm.offsetTop;
  //如果包裹 img 的父元素离顶部也有距离,那么也要把它加上
  while(elm = elm.offsetParent) { //注意这儿 offsetParent 返回的是元素不是数值,同时这儿是赋值语句
    tempTop += elm.offsetTop;
  }
  return tempTop;
}

function lazyLoad(imgs){
  //获取可视区域高度
  let viewHeight = document.documentElement.clientHeight;
  //获取滚动高度
  let scrollTopVal = document.documentElement.scrollTop || document.body.scrollTop;
  console.log(viewHeight, scrollTopVal)
  for(var i = 0; i < imgs.length; i++){
      if((viewHeight + scrollTopVal) > getTop(imgs[i])){
        imgs[i].src = imgs[i].getAttribute('data-src')
      }
  }
}

function useIntersectionObserve(imgList) {
  let obsever = new IntersectionObserver((entries) => {
    entries.forEach((item, index, arrSelf) => {
      console.log(entries)
      if(item.isIntersecting) {
        item.target.src = item.target.dataset.src;
        obsever.unobserve(item.target);
      }
    });
  });

  imgList.forEach((item) => {
    obsever.observe(item);
  });
}


export default {
  // 这两个个方案要求 img 标签有默认的高度,不然当一个页面出来就展示图片的情况下会一下展示很多图片,
  // 所以在使用懒加载方案时给 img 加默认高度
  // 单独使用普通懒加载方案
  lazyloadDefault(selector) {
    let imgList = document.querySelectorAll(selector);

    lazyLoad(imgList);
    window.onscroll = function() {
      lazyLoad(imgList);
    }
  },
  // 单独使用 IntersectionObserve
  lazyLoadIntersectionObserver(selector) {
    let imgList = document.querySelectorAll(selector);

    let obsever = new IntersectionObserver((entries) => {
      entries.forEach((item, index, arrSelf) => {
        console.log(entries)
        if(item.isIntersecting) {
          item.target.src = item.target.dataset.src;
          obsever.unobserve(item.target);
        }
      });
    });

    imgList.forEach((item) => {
      obsever.observe(item);
    });
  },
  // 多浏览器适配方案
  lazyLoadPolyfill(selector) {
    let imgList = document.querySelectorAll(selector);

    if(!window.IntersectionObserver) {
      lazyLoad(imgList);
      window.onscroll = function() {
        lazyLoad(imgList);
      }
    }else {
      useIntersectionObserve(imgList)
    }
  }
}

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。
列表为空,暂无数据

关于作者

漆黑的白昼

暂无简介

0 文章
0 评论
22 人气
更多

推荐作者

qq_E2Iff7

文章 0 评论 0

Archangel

文章 0 评论 0

freedog

文章 0 评论 0

Hunk

文章 0 评论 0

18819270189

文章 0 评论 0

wenkai

文章 0 评论 0

    我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
    原文