iT邦幫忙

第 11 屆 iT 邦幫忙鐵人賽

DAY 18
1
Modern Web

深入現代前端開發系列 第 18

Day18 探索 Browser API(中)- MutationObserver、IntersectionObserver

今天會介紹 MutationObserverIntersectionObserver 這兩個最近常見的 API。

MutationObserver

在實作 Virtual DOM,或是想要監聽 DOM 的變化,來改變對應的 model,MutationObserver 就是相當好用的函數。

MutationObserver 可以監聽 DOM 的變化,像是增刪、改變節點、Text node 變化等等。

透過宣告 callback 與 observe 函數,可以監聽 DOM node 裡頭的變化:

const mo = new MutationObserver((mutations) => {
  mutations.forEach(mutation => {
		// your code
  })
});

mo.observe(target);

裡頭的 mutation 會是一個 MutationRecord,可以拿到 mutation 的變化、類型等等。同時你也會發現,我們傳入的 handler 拿到的 mutations 其實是個陣列,這是因為 MutationObserver 並不會同步執行,也就是每當 DOM 產生變化就直接執行,而是等到當前的操作結束後才觸發一次,對效能來說比較好,目前瀏覽器的支援也越來越好了。

另外,在使用上也要記得如果不用的話要呼叫 disconnect 這個方法來停止監聽。

Vue 當中的 MutationObserver

在 vue 當中蠻有趣的實作是透過 MutationObserver 的方式來實作 nextTick。他的做法是這樣的:

var counter = 1;
var observer = new MutationObserver(nextTickHandler);
var textNode = document.createTextNode(String(counter))
observer.observe(textNode, {
  characterData: true
})
timerFunc = () => {
  counter = (counter + 1) % 2
  textNode.data = String(counter)
}

透過 MutationObserver 是 micro task 的特性,可以確保頁面渲染與數據更新會在同一個 task 當中執行。

不過在 iOS WebView 中似乎會遇到 MutationObserver 無法運作的問題,在 Vue 上也有相關的 issue

IntersectionObserver

IntersectionObserver 可以用來確認在 target 是否有進入當前的 viewport,在以往我們可能要用 scroll 來達到類似的效果,但監聽滾動事件就需要小心效能上的問題,尤其是如果用 getBoundingRect() 的話會觸發一次 layout,在 scroll event 裡面呼叫 getBoundingRect 聽起來就是抖抖的啊。

有了 IntersectionObserver 就可以很簡單地做到同樣的事。

什麼時候會想要使用 IntersectionObserver 呢?最常見的場景有:

  • 實作頁面無限滾動
  • 實作 Lazy loading
const io = new IntersectionObserver((entries) => {
  entries.forEach(entry => {
    if (entry.isIntersecting) {
      // do fetching
    }
  });
}, {
  root
  thresholds
});

io.observe(target);

一般的場景下,用 entry.isIntersecting 來判斷就已經足夠了,你也可以用 threshold 來決定怎樣的闕值算是可見。關於 threshold 的說明可以參考 MDN 的文件

如果比較舊的瀏覽器沒有 IntersectionObserver 的話,可以考慮用 polyfill,或是搭配 webpack 做動態載入,當沒有 IntersectionObserver API 才動態引入 polyfill。

結論

隨著瀏覽器的 API 越來越豐富,我們可以更專注在功能開發上,而不是煩惱實作時各種細節與效能,不過也因為這些 API 相對起來比較新的關係,有時候如果要相容其他瀏覽器反而綁手綁腳的。


上一篇
Day17 探索 Browser API (上)- requestIdleCallback
下一篇
Day19 探索 Browser API(下)- ServiceWorker, WebWorker 與其他
系列文
深入現代前端開發32

尚未有邦友留言

立即登入留言