Intersection Observer 簡介
在網站中常常需要偵測元件出現、消失在畫面中
的時機點來觸發
指定事件,舉例如是體驗互動、廣告數據追蹤、甚至可以用來 Performance tuning,想必都困擾過前端工程師們,也可能像我曾寫出了無數種程式碼來處理此需求,這多種程式碼常會影響 Main Thread 渲染速度或維護不易,直接我遇見 Intersection Observer API
拯救了我美好的人生。
Intersection Observer 適用場景
- 實作廣告版位,
監聽
版位 100% 出現在畫面時,觸發
曝光收費 - 實作 infinite scrolling 瀑布流,
監聽
出現指定元件時,觸發
載入下頁內容 - 實作 lazy-loading image (緩載入圖片),
監聽
圖片位置出現在畫面時,觸發
載入圖片
Intersection Observer 優點
- 將監聽運算事件移出 Main Thread,觸發事件 callback 才回 Main Thread 執行,降低渲染效能影響
- 更直觀的監聽觸發時機,替代
Scroll Event
+Element.getBoundingClientRect()
的錨點式監聽
兼容 90.81% 使用者使用的瀏覽器
如需支援到 IE 瀏覽器使用者,可以考慮使用 polyfill
從案例看痛點
動態變化的 Nav
- 為求視覺一致性,希望 Nav 能在依照當前畫面 Section 變化顏色,這樣顧客會很滿意,聽說客人滿意就會想買東西!
動作解析
- 在 Scroll 時要能偵測當前畫面屬於哪個 Section
- 往上滾動時,下個 Section 的上端接觸到 Nav 時就要切換顏色
- 往下滾動時,上個 Section 的下端接觸到 Nav 時就要切換顏色
容易發生痛點
- 在 Section height 是動態變化時候,需要動態取得 Section 精確的 height 才能計算出正確錨點
- 如果在 Scroll Event 多做這些判斷,將會讓 Main Thread 承受過多運算影響渲染效能
使用 Intersection Observer 實作
建立一個 Observer 需要給予 觸發事件(callback)
及指定 觸發時機(option)
const observer = new IntersectionObserver(callback, options);
觸發的時機點 => 元件出現在畫面 及 消失在畫面 時
root
指的是監聽的區塊,填入null
則使用預設的裝置 viewpoint,即是視覺上整個畫面rootMargin
可以用來刪減監聽的區塊,使用就如同 css margin 比如想以 Nav 邊界為觸發點可以將第一個參數設定為負的 Nav Heightthreshold
可以填入 0 ~ 1 的浮點數,在監聽元件出現比例
佔達到時則觸發事件,這邊設定 0 就代表在元件「剛出現」及「剛消失」時觸發
const navHeight = document.querySelector('nav');
const options = {
root: null,
rootMargin: `-${navHeight}px 0px 0px 0px`,
threshold: [0]
}
觸發時的動作、事件 => 變化 Nav 的顏色
- 觸發事件時會得到
IntersectionObserverEntry
物件,其中就有剛元件目前位置等等資料 isIntersecting
這個參數即是目前元件是可不可以互動的狀態,搭配上述提到的顯示比例threshold
為 0 時, isIntersecting 的 Bool 值就代表的「剛出現」跟「剛消失」兩種狀態const callback = (entries, observer) => { entries.forEach(entry => { let $nav = document.querySelector('nav'); if(entry.isIntersecting){ $nav.classList.add(entry.target.dataset.nav_class); }else{ $nav.classList.remove(entry.target.dataset.nav_class); } }); };
監聽的元件 => 每個 Section
- 將製作好的監聽者作用於每個 Section,讓它們在出現時新增 class,消失時自動移除 class 達到 Nav 顏色的動態切換
let $section1 = document.querySelector(`main section:nth-child(1)`); let $section2 = document.querySelector(`main section:nth-child(2)`); let $section3 = document.querySelector(`main section:nth-child(3)`); let $section4 = document.querySelector(`main section:nth-child(4)`); let $section5 = document.querySelector(`main section:nth-child(5)`); observer.observe($section1); observer.observe($section2); observer.observe($section3); observer.observe($section4); observer.observe($section5);
實際執行結果
- 因為是 codepen 嵌入畫面,觸發時機點好像沒很準確,想完整觀看結果的可以用此連結
See the Pen Intersection Observer Demo by Nick (@Nick0603) on CodePen.
小結
今天主是要基本介紹 Intersection Observer 在網頁互動中可以帶來的效果及配置方法,在後續幾篇文章想更近一步的討論 laze-loading image
或 廣告版位的曝光收費
的實現背後的 Intersection Observer 配製方法,希望大家會喜歡及可以一起瞭解下去。