如何把 MutationObserver RxJS 化?

使用 MutationObserver 可以監控 DOM 的變化,但他是 browser 原生 api,透過 callback function 回傳 mutation,有辦法將它改成 RxJS 的方式嗎?本篇將分享如何將原生的 MutationObserver RxJS 化。

法一:使用 Subject 來發布事件

概念非常簡單:

  1. 建立一個 mutationSubject$ ,接受的型態為 MutationObserver callback 回傳的 mutations
  2. 初始化一個 MutationObserver instance,讓他的 callback 可以透過 mutationSubject$ 發布 mutations
  3. 讓 MutationObserver 觀測 targetDOM 的變化
  4. 最後訂閱 mutationSubject$,就可以用 RxJS 的做法來處理 mutation 事件,比如說做 debounce
import { Subject } from 'rxjs';
import { debounceTime } from 'rxjs/operators';

const mutationSubject$ = new Subject<MutationRecord[]>();
const targetDOM = document.body;

const mutationObserver = new MutationObserver((mutations) => {
  mutationSubject$.next(mutations);
});
mutationObserver.observer(targetDOM, { attributes: true, subtree: true });

mutationSubject$
.pipe(
  debounceTime(200),
).subscribe((mutations) => {
  // do somethings...
});

法二:進一步將 MutationObserver 包成 Observable

如同方法一,但這個方法直接用一個 function 把 MutationObserver RxJS 化,做法更為簡潔,也實現在 unsubscribe 時自動呼叫 mutation.disconnect() 停止監聽,相對於法一可能要另外撰寫比較容易遺忘。此函數可以放到 project 中的 util 共享使用。

import { Observable } from 'rxjs'; 
import { debounceTime } from 'rxjs/operators';

const targetDOM = document.body;

const observeOnMutation = (target, config): Observable<MutationRecord[]> => {
  return new Observable((observer) => {
    const mutation = new MutationObserver((mutations, instance) => {
      observer.next(mutations);
    });
    mutation.observe(target, config);

    const unsubscribe = () => {
      mutation.disconnect();
    };
    return unsubscribe;
  });
}

const mutationObservable = observeOnMutation(targetDOM, { attributes: true, subtree: true })
.pipe(
  debounceTime(200),
).subscribe((mutations) => {
  // do somethings...
});

如果覺得我文章內容對你有幫助的話,請在文章後面幫我按 5 個讚!讓我知道大家都喜歡什麼內容哦!

範例原始碼在此下載:github

延伸閱讀:用 ForwardRef 解決在 Angular 中遇到的 bug

Written by J
雖然大學唸的是生物,但持著興趣與熱情自學,畢業後轉戰硬體工程師,與宅宅工程師們一起過著沒日沒夜的生活,做著台灣最薄的 intel 筆電,要與 macbook air 比拼。 離開後,憑著一股傻勁與朋友創業,再度轉戰軟體工程師,一手扛起前後端、雙平台 app 開發,過程中雖跌跌撞撞,卻也累計不少經驗。 可惜不是那 1% 的成功人士,於是加入其他成功人士的新創公司,專職開發後端。沒想到卻在採前人坑的過程中,拓寬了眼界,得到了深層的領悟。