Javascript 中的 Intersection Observer API 允許在頁面或容器中追蹤元素的能見度。
問題
瀏覽網頁時,我們會滾動其內容(通常是垂直方向的)。
螢幕右側有捲動條,讓我們追蹤頁面中的瀏覽進度。
網頁中,如果想要追蹤某些元素的能見度,可透過監聽 scroll 事件來對頁面的捲動做出反應:
window.addEventListener("scroll", () => { const scrollPosition = window.scrollY;
// 根據位置執行操作, // 根據能見度執行相關操作});這種方法可行,但有什麼問題?
- 事件監聽函式會在每一次滾動時不斷重複觸發,可能會讓主執行緒過載
- 為了判斷頁面上的元素是否可見,要先獲取其位置(例如使用
getBoundingClientRect()),再將其與頁面中的滾動位置比較,因此需要手動計算 - 如果想要判斷頁面可滾動容器中的元素是否可見,基於父元素的位置,也需要手動計算
Intersection Observer
Intersection Observer API 能自然地解決這些問題。
以根元素為基準,我們可在一個已定義的交集區內觀察元素。
當任何被觀察的元素進入或離開交集區時,可以執行回呼函式。
根元素
建立 IntersectionObserver 實例時,可以傳遞選項。
選項中,可以指定根元素:root。如果未指定,預設則為整個頁面;否則,它可以是任何可滾動的容器,用來監測某些元素的能見度。
const observer = new IntersectionObserver( callback, // 回呼函式 { // 根元素 root: document.getElementById("container"), },);回呼函式
建立 IntersectionObserver 實例時,儲存回呼函式。
此函式會在以下兩種情況下執行:
- 實例建立時
- 被觀察的元素進入或離開交集區時
它需要兩個參數:進入或離開交集區的元素,以及 IntersectionObserver 的實例:
const observer = new IntersectionObserver( (entries, observer) => {}, // 選項...);entries 中有一個元素陣列,每個元素都是 IntersectionObserverEntry 類型;我們可循環遍歷此陣列,並從中讀取有用資訊,例如:
isIntersecting, 是最方便的資訊:元素是否在交集區裡?intersectionRatio, 可能會有用:元素與根元素的交叉比例是多少?
觀察元素
觀察元素很簡單。建立 IntersectionObserver 實例後,呼叫 observe 函式並傳遞要觀察的元素:
observer.observe(element);然後,當元素進入或離開交集區時,回呼函式將被觸發。
交集區
預設情況下,交集區會覆蓋整個根元素。當被觀察的元素接觸到這個區域時,它將被視為能見。
const observer = new IntersectionObserver(callback);以上範例中,當元素進入區域時,將被視為能見。因此邏輯上來說,會讓人覺得所有元素似乎一直都是能見的。
rootMargin
可以透過傳遞選項來使交集區更大或更小:rootMargin。
rootMargin 選項接受與 CSS margin 屬性相同的語法:top right bottom left。因此可指定一到四個數值,以像素、百分比或以上兩者為單位。
讓我們看看一個使用 rootMargin 到 -100px 的範例,這會在四個方向上將交集區各縮小100像素:
const observer = new IntersectionObserver(callback, { rootMargin: "-100px",});嘗試使用以下捲動條。要縮小交集區,因此會套用負數值:
threshold
threshold 選項允許添加閾值,從而將元素視為能見。數值可用多種格式化:
0和1之間的數值等同於0%和100%之間的百分比。例如若設定傳遞0.8,則當元素至少有 80% 內容能見時,就將被視為能見。
使用 0.8 的例子:
const observer = new IntersectionObserver(callback, { threshold: 0.8,});- 使用一個
0到1之間的數值陣列,用來指定IntersectionObserver在哪些能見百分比時需觸發回呼函式。
例如:每 10% 觸發一次函式,並顯示元素的能見百分比(intersectionRatio):
const observer = new IntersectionObserver(callback, { threshold: [0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1],});Output :管理表目錄
Intersection Observer API 使用的一個例子是管理表目錄。
閱讀文章時,目前閱讀的章節會被用高亮突出顯示。
這就是 Astro Starlight 的執行方式:當某個章節標題進入指定的交集區時,對應的表目錄元素將被高亮突出顯示。
Astro Starlight 包含一個 web component。此組件包含 IntersectionObserver 實例的建立。
在此組件中,也能看到使用 rootMargin 選項計算交集區的方式:獲取導航欄的高度,添加行動裝置上表目錄的高度,作為交集區的起點;再往下 53 像素,則是該區的底部。當某個標題穿越這個區域時,對應的表目錄元素就將改變其外觀。
實際上 Astro Starlight 定義了兩個 web components:一個用於 行動裝置(顯示在螢幕頂部),另一個用於較大螢幕(顯示在右側)。