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
的預設選項,當元素有部分進入檢視畫面及完全離開可視區域時,系統就會呼叫回呼。
如果您需要觀察多個元素,建議您多次呼叫 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
我不太喜歡在元素內捲動,但我不會評斷,IntersectionObserver
也不會。options
物件會採用 root
選項,讓您將 viewport 以外的項目定義為根目錄。請注意,root
必須是所有觀測元素的祖系。
交集所有事物!
不可以!開發人員不良!這並非妥善使用使用者的 CPU 週期。以無限捲動器為例:在這種情況下,建議您在 DOM 中新增哨兵,並觀察 (和回收) 這些哨兵。您應在無限捲動畫面中,靠近最後一個項目的位置新增哨兵。當該哨兵進入檢視範圍時,您可以使用回呼來載入資料、建立下一個項目、將項目附加至 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
的原始用途。
我可以在回呼中進行多少工作?
簡短精要:在回呼中花費太多時間會導致應用程式延遲,所有常見做法都適用。
繼續前進,並與元素交叉
IntersectionObserver
的瀏覽器支援度良好,因為它可用於所有新式瀏覽器。如有需要,polyfill 可用於舊版瀏覽器,並在 WICG 存放區中提供。顯然,使用原生實作項目的 polyfill 不會帶來效能優勢。
您現在就可以開始使用 IntersectionObserver
!請告訴我們你發現的問題。