Bootstrap

性能优化利器❕ - 深入浅出IntersectionObserver系列

在这里插入图片描述

IntersectionObserver

IntersectionObserver(交叉观察器)是浏览器提供的一种API,用于检测一个元素是否出现在视口(viewport)内,或者与另一个元素或浏览器的边界相交。这个API非常有用,特别是在实现懒加载图片无限滚动页面或是其他基于可见性的交互效果时。


基本用法

1、创建观察器

const observer = new IntersectionObserver(entries => {
  entries.forEach(entry => {
    if (entry.isIntersecting) {
      // 元素在视口内
    }
  });
}, {
  threshold: 0.5 // 可以设置多个阈值,这里表示当元素50%出现在视口内时触发回调
});
  • 创建一个 IntersectionObserver 实例,并指定回调函数以及可选的配置对象

2、观察目标元素

observer.observe(targetElement);

使用 .observe() 方法来开始观察特定的DOM元素。


3、停止观察:

observer.unobserve(targetElement); // 停止观察单个元素
observer.disconnect(); // 断开观察器的所有观察
// 使用 .unobserve() 方法可以停止观察某个元素,
// 或者使用 .disconnect() 方法来完全断开观察器的所有观察。

4、配置项

  • root: 定义相对于哪个元素进行观察,默认为视口
  • rootMargin: 定义相对于根元素边缘的偏移量
  • threshold: 一个数值或数值数组,定义了何时调用回调函数。数值范围从0到1,分别代表没有交集和完全交集。

图片懒加载

假设你有一个包含许多图片的页面,但希望只有当图片进入视口时才加载它们。你可以使用 IntersectionObserver 来实现这样的懒加载功能:

const images = document.querySelectorAll('.lazy');
const observer = new IntersectionObserver((entries, observer) => {
  entries.forEach(entry => {
    if (entry.isIntersecting) {
      entry.target.src = entry.target.dataset.src; 
      // 设置图片的真实src
      observer.unobserve(entry.target); 
      // 不再观察已经加载的图片
    }
  });
}, {
  threshold: 0.5
});

images.forEach(img => observer.observe(img));

在这个例子中,当图片元素与视口至少有50%的交集时,就会被加载并从观察列表中移除

拓展:

使用 onscroll实现来懒加载

window.onscroll = function() {
  const images = document.querySelectorAll('.lazy:not(img[src])');
  images.forEach(img => {
    if (isInViewport(img)) {
      img.src = img.dataset.src;
    }
  });
};

function isInViewport(element) {
  const rect = element.getBoundingClientRect();
  return (
    rect.top >= 0 &&
    rect.left >= 0 &&
    rect.bottom <= (window.innerHeight || document.documentElement.clientHeight) &&
    rect.right <= (window.innerWidth || document.documentElement.clientWidth)
  );
}

在上述示例中,IntersectionObserver 版本更加简洁,同时也避免了在滚动时执行额外的计算,从而提高了性能


无限滚动

IntersectionObserver 也可以用来实现无限滚动,即当用户滚动到页面底部时自动加载更多内容

let observer = new IntersectionObserver((entries, observer) => {
  entries.forEach(entry => {
    if (entry.isIntersecting) {
      loadMore();
      observer.unobserve(entry.target);
    }
  });
});

observer.observe(document.querySelector('.footer'));

无限滚动的用处比较多

  • 社交媒体网站:在社交媒体网站上,可以使用无限滚动来加载用户的动态或新闻源的文章,使用户能够无限地向下滚动并加载更多内容
  • 电子商务网站:在商品列表页面,可以使用无限滚动来实现滚动到页面底部时自动加载更多商品,提供更好的浏览体验。
  • 新闻网站:在新闻列表或文章阅读页面,可以使用无限滚动来加载更多新闻或相关文章,使用户可以持续阅读感兴趣的内容。
  • 图片浏览器和相册:在图片浏览器或相册应用中,可以使用无限滚动来加载更多照片,使用户可以连续地查看图片。
  • 博客或论坛:在博客网站或论坛上,可以使用无限滚动来加载更多帖子或博客文章,让用户可以方便地浏览并获取更多信息。

首屏动画优化

页面动画当元素进入视口时触发动画效果,为页面增添交互与吸引力。

// 创建 IntersectionObserver 实例
const options = {
  root: null,
  rootMargin: '0px',
  threshold: 0.2 // 元素交叉区域达到视口20%时触发回调
};

const observer = new IntersectionObserver(callback, options);

// 定义回调函数
function callback(entries, observer) {
  entries.forEach(entry => {
    if (entry.isIntersecting) {
      const element = entry.target;
      element.classList.add('animate'); // 添加动画类或样式,触发动画效果

      observer.unobserve(element); // 停止观察该元素
    }
  });
}

// 找到所有需要触发动画效果的元素
const elements = document.querySelectorAll('.animated-element');

// 将元素添加到 IntersectionObserver 中进行观察
elements.forEach(element => {
  observer.observe(element);
});

当元素进入视口并与视口的交叉区域达到预设的阈值时,回调函数会被触发。在回调函数中,可以使用 entry.target 来访问触发动画效果的元素。
在这个示例中,我们使用 element.classList.add('animate') 来添加动画类或样式,从而触发元素的动画效果。通过调整 IntersectionObserver 实例的 threshold 属性,可以控制什么时候触发动画效果。

  • 例如,将 threshold 设置为 0.5 表示元素至少与视口有一半交叉时触发动画。这种页面动画效果可以应用于多种场景,

  • 例如:首屏加载动画:当页面加载完成后,逐个触发元素进入视口时添加动画效果,增添页面的过渡效果。

  • 滚动加载动画:当页面滚动到某个特定区域时,触发该区域内的元素添加动画效果,提高用户体验。

  • 图片懒加载动画:当图片进入视口时,添加动画效果显示图片,提升页面的视觉吸引力。

注意,在使用动画效果时要注意性能和用户体验,避免过多或复杂的动画效果影响页面加载速度和流畅度。


好处

  • 更好的性能:传统的监听滚动事件方式可能会导致频繁的计算,影响页面性能。而 IntersectionObserver 是浏览器原生提供的API,它使用异步执行,可以更高效地监听元素是否进入视口,减少了不必要的计算和性能开销。
  • 减少代码复杂性:IntersectionObserver可以简化代码逻辑。使用传统的方式监听滚动事件需要手动计算元素的位置、判断元素是否进入视口,以及处理滚动事件的节流等。而通过IntersectionObserver,只需定义回调函数,在元素进入或离开视口时触发相应操作,大大简化了代码
  • 支持懒加载和无限滚动:IntersectionObserver可以实现图片懒加载无限滚动等常见效果。当元素进入视口时,可以延迟加载图片或触发数据请求,避免不必要的资源加载,提升页面加载速度和性能。
  • 更精确的可见性控制:IntersectionObserver提供了更精确的可见性控制。通过设置合适的阈值(threshold),可以灵活地控制元素与视口的交叉区域达到多少时触发回调。这使得开发者可以根据需求来定义元素何时被认为是进入或离开视口,从而触发相应的操作。
;