iT邦幫忙

2022 iThome 鐵人賽

DAY 20
0
自我挑戰組

菜鳥前端修練之旅系列 第 20

Day 20 | IntersectionObserver

  • 分享至 

  • xImage
  •  

最近在做無限滾動(Infinite Scroll)的時候發現了 IntersectionObserver 這個好東西。以往在使用上要計算高度、檢查元素是否進入視窗等,使用這個 Web API 能夠讓我們更方便的去達成、同時效能也更好。

因為接下來的文章的是以筆記型式撰寫,詳細的教學請參考這兩篇:

創建 IntersectionObserver

使用 new 來建立 IntersectionObserver ,並帶入兩個參數:callbackoptions

let observer = new IntersectionObserver(callback, options);

首先看看參數 options

options

options 這個參數又可以設定三個屬性,分別是:

  • root:觀察窗口,預設為 null(以瀏覽器的 viewport 為範圍)。
  • rootMargin:同 CSS 的 margin。
  • threshold:觸發門檻,可填入 0 - 1 之間的數字或是陣列型式 [0, 0.2, 0.6, 1]
const opition = {
    root : null,
    rootMargin: "0px 0px 0px 0px",
    threshold: 0
};

callback

callback 接受兩個參數,分別是 entriesobserver

// 取得 DOM
const imgs = document.querySelectorAll('img')

// 建立 IntersectionObserver
const observer = new IntersectionObserver((entries, observer) => {  
  entries.forEach((entry) => {    
    // ...
  })
}, opition)

// 監聽每個 img
imgs.forEach(img => observer.observe(img)) 
  • entries:entries 的清單,包含了各個物件中的資訊。以下為 console.log(entries) 的結果。

  • observer:參照到 observer 本身,進行停止觀察等行為。

將剛剛 console.log(entries) 其中的內容展開後可以發現幾個實用的方法。

  • entry.isIntersecting:確認元素是否進入 viewport,回傳 truefalse
  • entry.intersectionRect:被觀察對象的左上角在 viewport 的距離。
  • entry.intersectionRatio:元素有多少比例在 viewport 中(0 到 1)。
  • entry.target:元素本身。

取消觀察 unobserve

上面的程式碼使用 observe() 來觀察,相反的如果已達成條件、不需要再觀察的話,使用 unobserve 即可。

observer.unobserve(element);

實作 無限滾動(Infinite Scroll)

這邊簡單製作一個不斷載入狗圖片的程式,首先 HTML 長這樣:

<ul>
    <li><img src="./images/dog.jpg" alt="狗圖"></li>
    <li><img src="./images/dog.jpg" alt="狗圖"></li>
    <li><img src="./images/dog.jpg" alt="狗圖"></li>
    <li><img src="./images/dog.jpg" alt="狗圖"></li>
    <li><img src="./images/dog.jpg" alt="狗圖"></li>
    <li><img src="./images/dog.jpg" alt="狗圖"></li>
</ul>

ul 中放了一堆 li,之後的過程只要不斷增加 li 就好。這邊提供兩個方式去實作:

【方法一】 在底部增加一個元素,判斷這個元素是否進入視窗。
【方法二】 不斷去抓最後一個 li 的 DOM,再觀察這個 DOM 是否進入視窗。

我採用方法一來實作,直接在 HTML 底下增加一個 <div id="obj"></div>

// 以上略 ...
    <li><img src="./images/dog.jpg" alt="狗圖"></li>
    <li><img src="./images/dog.jpg" alt="狗圖"></li>
</ul>

// 觀察這個 div
<div id="obj"></div>

接著是 JavaScript,我們針對 #obj 來監聽,看它是不是進入視窗,如果進入的話直接增加一個 li,範例如下:

const list = document.querySelector("ul");
const obj = document.querySelector('#obj');

const opition = {
    root: null,
    rootMargin: "0px 0px 0px 0px",
    threshold: 0
};

const observer = new IntersectionObserver((entries) => {
    entries.forEach(entry => {
        if (entry.isIntersecting) {
            // 當 obj 進入視窗後,增加 li
            list.innerHTML += '<li><img src="./images/dog.jpg" alt="狗圖"></li>'
        }
    })
}, opition);

// 監聽 obj
observer.observe(obj);

可以發現只要滑到最底下就會再新增一個 li

這邊簡易示範了無限載入,如果是要接 API 的資料、或是想增加 CSS 動畫等需求的話,再請各位自行修改囉。

參考資料


上一篇
Day 19 | Debounce & Throttle
下一篇
Day 21 | 前端中的 Hash & History
系列文
菜鳥前端修練之旅30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言