IntersectionObserver'即將進入美景

IntersectionObservers 可讓您在觀察到的元素進入或離開瀏覽器可視區域時通知您。

瀏覽器支援

  • 51
  • 15
  • 55
  • 12.1

資料來源

假設您想追蹤 DOM 中的元素進入可見檢視區的時機。我們建議這麼做,以便適時延遲載入圖片,或確定使用者是否確實正在查看特定廣告橫幅。方法是啟動捲動事件,或使用定期計時器,在該元素上呼叫 getBoundingClientRect()

不過,這個方法會花費許多時間,因為每次呼叫 getBoundingClientRect() 都會強制瀏覽器重新調整整個網頁的版面配置,為網站帶來大量資源浪費。如果您知道網站正在 iframe 中載入,且您想知道使用者何時能看到特定元素,案件就幾乎是不可能的。「單一來源模型」和瀏覽器無法讓您從含有 iframe 的網頁存取任何資料。這是常見的問題 (例如使用 iframe 載入的廣告)。

IntersectionObserver專為所有新式瀏覽器所設計的體驗,想讓這項瀏覽權限測試更有效率。IntersectionObserver 會在觀察到的元素進入或離開瀏覽器的可視區域時通知您。

iframe 顯示設定

如何建立 IntersectionObserver

API 規模很小,且最好能舉例說明:

const io = new IntersectionObserver(entries => {
  console.log(entries);
}, {
  /* Using default options. Details below */
});

// Start observing an element
io.observe(element);

// Stop observing an element
// io.unobserve(element);

// Disable entire IntersectionObserver
// io.disconnect();

如果使用 IntersectionObserver 的預設選項,當元素部分進入檢視畫面及完全離開可視區域時,系統會同時呼叫回呼。

如果您需要觀察多個元素,可以多次呼叫 observe() 來觀察使用相同 IntersectionObserver 例項的多個元素。

entries 參數會傳遞到回呼,這個回呼是 IntersectionObserverEntry 物件的陣列。每個這類物件都包含其中一個觀察元素的最新交集資料。

🔽[IntersectionObserverEntry]
    time: 3893.92
    🔽rootBounds: ClientRect
        bottom: 920
        height: 1024
        left: 0
        right: 1024
        top: 0
        width: 920
    🔽boundingClientRect: ClientRect
    // ...
    🔽intersectionRect: ClientRect
    // ...
    intersectionRatio: 0.54
    🔽target: div#observee
    // ...

rootBounds 是對根元素 (預設為可視區域) 呼叫 getBoundingClientRect() 的結果。boundingClientRect 是對觀察到的元素呼叫 getBoundingClientRect() 的結果。intersectionRect 是這兩個矩形的交集,會有效地告訴您觀察到元素的哪個部分可見。intersectionRatio 具有密切關聯,會顯示元素的顯示比例。有了這些資訊,您現在可以導入素材資源,在素材資源顯示於畫面上之前立即載入內容。效率極佳。

十字路口比例。

IntersectionObserver 會以非同步方式提供資料,而您的回呼程式碼會在主執行緒中執行。此外,規格實際上表示 IntersectionObserver 實作應使用 requestIdleCallback()。也就是說,對您提供的回呼進行的呼叫優先順序較低,且會在閒置期間由瀏覽器發出。這是一項謹慎的設計決定。

捲動的 div

我不太喜歡捲動元素內部,但我不是在這裡判斷,也不是IntersectionObserveroptions 物件使用 root 選項,可讓您將可視區域的替代項目定義為根層級。請注意,root 需要是所有觀察元素的祖系。

融入所有元素!

不!這位開發人員可能很糟糕!這並不在乎使用者的 CPU 週期用量。讓我們以無限捲頁為例:在這種情況下,最好將 sentinels 加入 DOM,並觀察 (並回收!) 那些。您應在無限捲動器的最後一個項目附近新增傳送端。當 sentinel 進入檢視畫面後,您可以使用回呼載入資料、建立下一個項目、將這些項目附加至 DOM,並視情況重新放置傳送器。如果正確回收傳送器,則無需額外呼叫 observe()IntersectionObserver 可以正常運作。

無限捲動器

敬請期待更多最新消息

如前文所述,當觀察到的元素部分進入檢視區塊時,會觸發回呼一次,而另一個則是離開可視區域時。這麼一來,IntersectionObserver 就會回答「顯示 X 元素是否在畫面中?」這個問題的答案。但在某些用途中,這可能不足以滿足您的需求。

這時 threshold 選項就能派上用場。可讓您定義 intersectionRatio 門檻的陣列。每當 intersectionRatio 跨越其中一個值時,系統就會呼叫回呼。threshold 的預設值為 [0],表示預設行為。如果將 threshold 變更為 [0, 0.25, 0.5, 0.75, 1],每當元素出現額外四分之一的畫面時,我們就會通知我:

門檻動畫。

還有其他方法嗎?

目前,上述項目只有一個其他選項。rootMargin 可讓您指定根的邊界,有效地擴大或縮小用於交集的區域。這些邊界是使用 CSS 樣式字串 á la "10px 20px 30px 40px" 指定,分別指定上、右、下和左邊界。總結來說,IntersectionObserver 選項結構提供下列選項:

new IntersectionObserver(entries => {/* … */}, {
  // The root to use for intersection.
  // If not provided, use the top-level document's viewport.
  root: null,
  // Same as margin, can be 1, 2, 3 or 4 components, possibly negative lengths.
  // If an explicit root element is specified, components may be percentages of the
  // root element size.  If no explicit root element is specified, using a
  // percentage is an error.
  rootMargin: "0px",
  // Threshold(s) at which to trigger callback, specified as a ratio, or list of
  // ratios, of (visible area / total area) of the observed element (hence all
  // entries must be in the range [0, 1]).  Callback will be invoked when the
  // visible ratio of the observed element crosses a threshold in the list.
  threshold: [0],
});

<iframe>魔法

IntersectionObserver 是特別為廣告服務和社交網路小工具所設計,這些小工具經常使用 <iframe> 元素,因此不論裝置是否在畫面中顯示,都能因此獲益良多。如果 <iframe> 觀察到其中一個元素,則只要捲動 <iframe> 以及捲動包含 <iframe> 的視窗,系統就會在適當時機觸發回呼。不過,在後者中,rootBounds 會設為 null,以免來源間外洩。

哪個 IntersectionObserver「不要」

需注意的是,IntersectionObserver 原本設計成沒有完美的像素,也不代表低延遲。使用這些動畫實作捲動式動畫等目標時,系統會繫結至失敗,因為資料將會 (嚴格解讀) 沒有時間限制,屆時您才能使用這些資料。如要進一步瞭解 IntersectionObserver 的原始用途,請參閱這篇文章

我可以在回呼中執行多少工作?

Short 'n Sweet:在回呼中花費太多時間會導致應用程式延遲,而且所有通用做法都適用。

捲動網頁並彼此交錯

瀏覽器支援 IntersectionObserver適用於所有新版瀏覽器。必要時,可在舊版瀏覽器中使用 polyfill,並可在 WICG 存放區中找到。顯然,採用原生實作提供的 polyfill 無法享有效能優勢。

現在可以開始使用 IntersectionObserver 了!與我們分享你的想法。