Day01 監聽“可見狀態”事件 - Intersection Observer API


Day01 監聽“可見狀態”事件 - Intersection Observer API

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 Height
  • threshold 可以填入 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 嵌入畫面,觸發時機點好像沒很準確,想完整觀看結果的可以用此連結
    <p class="codepen" data-height="499" data-theme-id="dark" data-default-tab="js,result" data-user="Nick0603" data-slug-hash="OJVVKvg" style="height: 499px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;" data-pen-title="Intersection Observer Demo"> <span>See the Pen <a href="https://codepen.io/Nick0603/pen/OJVVKvg"> Intersection Observer Demo</a> by Nick (<a href="https://codepen.io/Nick0603">@Nick0603</a>) on <a href="https://codepen.io">CodePen</a>.</span> </p><script async src="https://static.codepen.io/assets/embed/ei.js"></script>

小結

今天主是要基本介紹 Intersection Observer 在網頁互動中可以帶來的效果及配置方法,在後續幾篇文章想更近一步的討論 laze-loading image廣告版位的曝光收費 的實現背後的 Intersection Observer 配製方法,希望大家會喜歡及可以一起瞭解下去。

參考資料

#Web #javascript #Web API #IntersectionObserver #Optimize tuning





近期正式轉職成為一個前端工程師 在工作的 Code Base 看多許多從未使用過的 Web API 想透過此次黑客松來翻翻文件 並把感覺實用、有趣的學習並紀錄起來 ~

留言討論