使用 MutationObserver 可以監控 DOM 的變化,但他是 browser 原生 api,透過 callback function 回傳 mutation,有辦法將它改成 RxJS 的方式嗎?本篇將分享如何將原生的 MutationObserver RxJS 化。
法一:使用 Subject 來發布事件
概念非常簡單:
- 建立一個 mutationSubject$ ,接受的型態為 MutationObserver callback 回傳的 mutations
- 初始化一個 MutationObserver instance,讓他的 callback 可以透過 mutationSubject$ 發布 mutations
- 讓 MutationObserver 觀測 targetDOM 的變化
- 最後訂閱 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