IntersectionObserver 可讓您知道觀察的元素何時進入或離開瀏覽器的可視區域。
假設您想追蹤 DOM 中的元素何時進入可見的可視區域。您可能需要這麼做,才能及時延遲載入圖片,或需要知道使用者是否確實正在查看特定廣告橫幅。方法是連結捲動事件,或使用週期性計時器,並在該元素上呼叫 getBoundingClientRect()。
不過,這種做法非常緩慢,因為每次呼叫 getBoundingClientRect() 都會強制瀏覽器重新配置整個網頁,並在網站中引入大量卡頓。如果網站是在 iframe 內載入,而您想知道使用者何時能看到某個元素,這幾乎是不可能的任務。單一來源模型和瀏覽器不允許您存取包含 iframe 的網頁資料。這類問題常見於廣告,例如經常使用 iframe 載入的廣告。
IntersectionObserver 的設計目的是提高這項可見度測試的效率,且已在所有新式瀏覽器中推出。IntersectionObserver 可讓您知道觀察到的元素何時進入或離開瀏覽器的可視區域。
如何建立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 的預設選項時,當元素部分進入檢視畫面,以及完全離開可視區域時,系統都會呼叫回呼。
如果您「需要」觀察多個元素,建議您使用「相同」IntersectionObserver 執行個體,多次呼叫 observe() 來觀察多個元素。
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
我不太喜歡在元素內捲動,但我不是來評斷的,IntersectionObserver 也不是。options 物件會採用 root 選項,讓您定義可視區域的替代項目做為根層級。請務必注意,root 必須是所有觀測元素的前身。
交集所有項目!
才不是!開發人員太不小心了!這並非使用使用者 CPU 週期的明智做法。以無限捲動器為例:在這種情況下,建議您在 DOM 中加入哨兵,並觀察 (和回收!) 這些哨兵。您應該在無限捲動器中,靠近最後一個項目的位置新增一個標記。當該標記進入檢視畫面時,您可以使用回呼載入資料、建立下一個項目、將其附加至 DOM,並據此重新定位標記。如果正確回收 sentinel,就不需要額外呼叫 observe()。IntersectionObserver會繼續運作。
請提供更多更新
如前所述,當觀察元素部分進入檢視區塊時,回呼會觸發一次,而當元素離開檢視區塊時,回呼會再次觸發。這樣一來,IntersectionObserver 就能回答「元素 X 是否在檢視畫面中?」這個問題。不過,在某些用途中,這可能不夠。
這時 threshold 選項就能派上用場。可讓您定義 intersectionRatio 門檻陣列。每當 intersectionRatio 超過其中一個值時,系統就會呼叫回呼。threshold 的預設值為 [0],這說明瞭預設行為。如果將 threshold 變更為 [0, 0.25, 0.5, 0.75, 1],則每當元素多顯示四分之一時,我們就會收到通知:
還有其他選項嗎?
目前除了上述選項外,只有一個額外選項。rootMargin 可讓您指定根層級的邊界,有效擴大或縮小用於交集的區域。這些邊界是使用 CSS 樣式字串指定,例如 "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> magic
IntersectionObserver 是專為廣告服務和社群網路小工具設計,這些服務和小工具經常使用 <iframe> 元素,且可透過瞭解是否在檢視畫面中受益。如果 <iframe> 觀察到其中一個元素,則捲動 <iframe> 以及捲動 包含 <iframe> 的視窗,都會在適當的時間觸發回呼。不過,在後者的情況下,rootBounds 會設為 null,以免資料跨來源外洩。
IntersectionObserver「不」包含哪些內容?
請注意,IntersectionObserver 刻意不追求完美像素或低延遲。如果使用這些方法來實作捲動相關動畫等作業,一定會失敗,因為嚴格來說,資料在使用時已經過時。如要進一步瞭解 IntersectionObserver 的原始用途,請參閱說明文件。
我可以在回呼中執行多少工作?
簡短:在回呼中花費太多時間會導致應用程式延遲,所有常見做法都適用。
開始交集元素
IntersectionObserver 的瀏覽器支援良好,因為所有新式瀏覽器都支援。如有需要,您可以在舊版瀏覽器中使用 Polyfill,並在 WICG 的存放區中取得。顯然,使用該 polyfill 不會獲得原生實作帶來的效能優勢。
你可以立即開始使用 IntersectionObserver!請告訴我們你的想法。