IntersectionObserver API 实现返回顶部功能

590 阅读2分钟

需求:点击“回到顶部”按钮,返回H5页面的顶部。

1. 思路剖析

  • 具体交互:滚动页面,当 区域A 进入了视口(viewport),即用户可见范围,则显示“回到顶部”按钮,否则,隐藏“回到顶部”按钮。
  • 传统思路:监听滚动事件,频繁调用 Element.getBoundingClientRect() 方法以获取区域A的边界信息。但事件监听和调用 Element.getBoundingClientRect() 都是在主线程上运行,频繁触发、调用可能会造成性能问题。
  • 新思路:联想到 IntersectionObserver API,它可用于相交检测,即检测一个元素是否可见或者两个元素是否相交。

2. 关于 IntersectionObserver API

  • Intersection Observer API 会注册一个回调函数,每当被监视的元素进入或者退出另外一个元素时(或者 viewport),或者两个元素的相交部分大小发生变化时,该回调方法会被触发执行。
  • 适用的业务场景:图片懒加载、内容无限滚动、在用户看见某个区域时执行任务或播放动画等。

3. 代码实战

/**
 * @description: 点击“回到顶部”按钮,滚动至页面顶部
 * @param {string} scrollToTopBtnElId “回到顶部”按钮元素ID
 * @param {string} targetElId 目标元素ID,监控该目标是否进入当前屏幕,若是,显示按钮
 */
export function useScrollToTop (scrollToTopBtnElId: string, targetElId: string): void
{
  // “回到顶部”按钮元素
  const scrollToTopBtn = document.getElementById(scrollToTopBtnElId) as HTMLElement;
  // 目标元素
  const target = document.getElementById(targetElId) as HTMLElement;

  // 滚动至页面顶部
  const scrollToTop = () =>
  {
    const scrollTop = document.documentElement.scrollTop || document.body.scrollTop;

    if (scrollTop > 0)
    {
      window.scrollTo(0, 0);
    }
  };

  // 观察器的回调函数
  function callback (entries: any, observer: any)
  {
    // entries 保存被观察的对象,一个观察器可观察多个 DOM 节点
    entries.forEach((entry: any) =>
    {
      // 判断当前元素是否可见
      if (entry.isIntersecting)
      {
        // 显示“回到顶部”按钮
        scrollToTopBtn.classList.add('show-btn');
      }
      else
      {
        // 隐藏“回到顶部”按钮
        scrollToTopBtn.classList.remove('show-btn');
      }
    });
  }

  // 初始化一个观察器实例
  const observer = new IntersectionObserver(callback);
  if (target)
  {
    // 开始观察
    observer.observe(target);
  }

  if (scrollToTopBtn)
  {
    // 给“回到顶部”按钮元素绑定点击事件
    scrollToTopBtn.addEventListener('click', scrollToTop);
  }
}
参考文档