IntersectionObserver v2版本

空山與新雨發表於2023-10-18

業務需要內容展示後日誌打點,於是使用到了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。

相關文章