跳转到正文
Monster Cone
返回

JavaScript 懒加载实战:图片与动画的性能优化方案

编辑页面

懒加载是前端一种常见的优化手段,下面将介绍两种常见的懒加载实现

方法一 (getBoundingClientRect API)

该方法优点是兼容性较好,所有浏览器都支持。代码如下

const innerHeight = window.innerHeight;
const debounce = (func, delay = 200) => {
  let timer;
  return function (...args) {
    const context = this;
    clearTimeout(timer);
    timer = setTimeout(() => {
      func.apply(context, args);
    }, delay);
  };
};
const lazyLoading = () => {
  let imgs = [...document.querySelectorAll("img")];
  imgs.forEach(el => {
    const { top, height } = el.getBoundingClientRect();
    if (innerHeight - top > 0) {
      el.classList.add("animation");
      el.src = el.dataset.src;
    }
    if (top + height < 0 || top > innerHeight) {
      el.classList.remove("animation");
    }
  });
};
window.addEventListener("scroll", debounce(lazyLoading, 300), false);
window.onload = lazyLoading;

使用 getBoundingClientRect 获取元素高度和距离顶部的距离,计算是否在可视区内,如果在可视区内就给图片设置 src 属性或者添加动画 class,如果不在可视区内就移除动画 class,使元素在下次滚动到可视区时还能有动画效果。因为有些图片一开始就在顶部,这时候并不会触发 scroll 事件,就需要在页面加载完成时调用一次 lazyLoading 方法。

优化点:如果只需要使用图片懒加载,可以将选择器改为 document.querySelectorAll(“img[src=”]”),这样只会遍历还没加载图片的 img 元素。

方法二 (IntersectionObserver API)

IntersectionObserver 不支持 IE 浏览器,也不支持一些低版本的浏览器,但在今日,对于一些主流的浏览器兼容是足够的。它更容易实现。代码如下

let observer;
const loadImage = entries => {
  entries.forEach(entry => {
    if (entry.intersectionRatio > 0) {
      const { src } = entry.target.dataset;
      entry.target.src = src;
      entry.target.classList.add("animation");
    } else {
      entry.target.classList.remove("animation");
    }
  });
};
window.onload = () => {
  observer = new IntersectionObserver(loadImage);
  let imgs = [...document.querySelectorAll("img")];
  imgs.forEach(el => {
    observer.observe(el);
  });
};

首先我们在页面加载完成时注册一个 IntersectionObserver 实例,同时获取所有的 img 元素并使用 IntersectionObserver 实例进行监听。callback 通常会在元素进入视口和离开视口时触发,如果你在实例化 IntersectionObserver 的时候配置了 threshold 属性,它也会在 threshold 条件下触发。

回调函数接受两个参数,一个 IntersectionObserverEntry 对象,一个触发 IntersectionObserver 的实例

IntersectionObserverEntry 中包含如下属性

我们只需要 intersectionRatio 相交比例,在它大于 0 时我们设置 img 标签的 src 属性或者动画 class,在等于 0 时移除动画 class。

优化点:如果只需要使用图片懒加载,可以在设置了 src 属性后通过 observer.unobserve 方法移除元素的监听。

可以根据兼容性需要选择合适的实现方案


编辑页面
分享这篇文章:

上一篇
Ubuntu 开发环境初始化脚本:一键安装 Git、Docker 和 Nginx
下一篇
Promise Pool 实战:优雅控制异步并发数量