
最近在做無限滾動(Infinite Scroll)的時候發現了 IntersectionObserver 這個好東西。以往在使用上要計算高度、檢查元素是否進入視窗等,使用這個 Web API 能夠讓我們更方便的去達成、同時效能也更好。
因為接下來的文章的是以筆記型式撰寫,詳細的教學請參考這兩篇:
使用 new 來建立 IntersectionObserver ,並帶入兩個參數:callback 和 options。
let observer = new IntersectionObserver(callback, options);
首先看看參數 options:
options 這個參數又可以設定三個屬性,分別是:
null(以瀏覽器的 viewport 為範圍)。[0, 0.2, 0.6, 1]。const opition = {
root : null,
rootMargin: "0px 0px 0px 0px",
threshold: 0
};
callback 接受兩個參數,分別是 entries 和 observer:
// 取得 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 的清單,包含了各個物件中的資訊。以下為 console.log(entries) 的結果。
observer 本身,進行停止觀察等行為。將剛剛 console.log(entries) 其中的內容展開後可以發現幾個實用的方法。

entry.isIntersecting:確認元素是否進入 viewport,回傳 true 或 false。entry.intersectionRect:被觀察對象的左上角在 viewport 的距離。entry.intersectionRatio:元素有多少比例在 viewport 中(0 到 1)。entry.target:元素本身。上面的程式碼使用 observe() 來觀察,相反的如果已達成條件、不需要再觀察的話,使用 unobserve 即可。
observer.unobserve(element);
這邊簡單製作一個不斷載入狗圖片的程式,首先 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 動畫等需求的話,再請各位自行修改囉。