IntersectionObserver v2版本

发布时间 2023-10-18 22:15:15作者: 空山与新雨

业务需要内容展示后日志打点,于是使用到了IntersectionObserver,实践中发现一个问题:如果内容出现在了可视区内,但是被其他元素遮挡住了,这时候仍然会打日志。

于是寻找解决方案,发现IntersectionObserver 还有一个v2版本,刚好能解决这个问题。

在v2版本中,IntersectionObserverEntry对象数组的每一项都包含一个isVisible属性,该属性标识当前元素是否可见。当设置opacity, filter, transform或者被其他元素遮挡导致元素不可见时,该属性为false;

要开启该功能,需要在IntersectionObserver的配置参数中增加两个属性: trackVisibility delay

{
  trackVisibility: true,
  delay: 100,  // 最小100
}

下面是一个示例代码:

<div id="root">
  <p></p><p></p><p></p><p></p><p></p><p></p><p></p><p></p><p></p><p></p><p></p><p></p><p></p><p></p><p></p><p></p><p></p><p></p>
</div>
<script>
  // 观察根元素和被观察目标元素的交叉情况
  const observer = new IntersectionObserver(
    (entries, observer) => {
      entries.forEach((entry) => {
        if (entry.isVisible && entry.isIntersecting) {
          entry.target.innerHTML = "loaded";
          // observer.unobserve(entry.target); // 停止观察目标元素
        } else {
          entry.target.innerHTML = "unloaded";
        }
      });
    },
    {
      // rootMargin 默认值为” 0px 0px 0px 0px “,可用百分比,相当扩展根元素的对应宽高的百分比的值;
      // 可以是负值。正数的时候代表在回调会更早触发,为负值代表回调更晚触发。 为了避免出现空白,可以设置为正值
      rootMargin: "-40px 0px -40px 0px ", 
      // root 被观察对象的祖先元素,也就是根元素;默认是浏览器的视口窗口 
      root: document.querySelector("#root"), 
      // threshold一个包含阈值的数组,比如,[0, 0.25, 0.5, 0.75, 1]就表示当目标元素 0%、25%、50%、75%、100% 可见时,会触发四次回调函数, 
      // 数组中的每个阈值可以是 0~1 之间的任意数值,默认值为[0],也就是开始进入,就会触发。
      threshold: [1], 
      trackVisibility: true,
      delay: 1000,
    }
  );
  const pEl = document.querySelectorAll("p");
  pEl.forEach((item) => observer.observe(item));
</script>
<style>
  * {
    margin: 0;
    padding: 0;
  }
  div {
    height: 400px;
    overflow: auto;
    box-shadow: 0 0 2px 0px rgba(255, 0, 0, 1);
    margin-left: 10px;
  }
  p {
    height: 50px;
    width: 400px;
    margin: 10px;
    border: 1px solid darkseagreen;
    /* opacity: 0.8; */
  }
</style>

需要注意的是:该isVisible的判断比较保守,例如 filter: grayscale(0.01%)opacity: 0.99 设置也会isVisible为false。