面試官:MutationObserver與IntersectionObserver 傻傻分不清楚?
Hello,大家好,我是 Sunday。
昨天,有位同學在面試的時候被問到:“MutationObserver 和 IntersectionObserver 的差異以及作用場景”。
所以,咱們今天就把這塊給大家統一解釋一下!
1. MutationObserver 和 IntersectionObserver 的區別
MutationObserver
- 作用:用于監聽 DOM 樹的變動,包括:元素的屬性、子元素列表或節點文本的變化。
- 適用場景:可以用來檢測 DOM 的結構和內容變化,比如元素被插入或刪除、屬性被更改等。
- 性能:由于 MutationObserver 監聽的是整個 DOM 樹的變化,頻繁的 DOM 操作會導致性能問題,因此適用于較少變化的場景。
IntersectionObserver
- 作用:用于監聽目標元素與其祖先元素(或 viewport)之間的交叉狀態,即是否進入或離開視口。
- 適用場景:適合用于檢測元素是否在視口中,例如:實現圖片懶加載、無限滾動或曝光監測。
- 性能:由于它的監聽目標是元素的可見性,相較于 MutationObserver,更適合頻繁變化的場景。
特性 | MutationObserver | IntersectionObserver |
監聽對象 | DOM 節點的結構、屬性或文本變化 | 目標元素與視口或指定元素的交叉狀態 |
常見使用場景 | 檢測 DOM 變化(插入、刪除、修改) | 圖片懶加載、曝光監測、滾動加載等 |
性能 | 頻繁變化可能影響性能 | 更適合高頻率變化的監聽 |
2. 應用場景
IntersectionObserver
在之前我們做圖片懶加載的時候,其實是使用過 IntersectionObserver 的。我們會使用它檢測 DOM(img) 是否可見,以此來判斷是否需要加載對應的圖片:
// 懶加載圖片的回調函數,包含淡入效果和錯誤處理
function lazyLoadImages(entries, observer) {
entries.forEach(entry => {
// 檢查圖片是否進入視口
if (entry.isIntersecting) {
const img = entry.target;
img.src = img.dataset.src; // 將 data-src 替換為 src 開始加載圖片
// 圖片加載成功后,添加 'loaded' 類觸發淡入效果
img.onload = () => img.classList.add('loaded');
// 圖片加載失敗時,顯示默認占位圖
img.onerror = () => img.src = 'placeholder.jpg';
observer.unobserve(img); // 停止觀察該圖片
}
});
}
// 創建 IntersectionObserver 實例,用于懶加載
const imageObserver = new IntersectionObserver(lazyLoadImages, { threshold: 0.1 });
// 選取所有帶有 data-src 屬性的圖片并開始觀察
document.querySelectorAll('img[data-src]').forEach(img => {
imageObserver.observe(img);
});
除此之外,IntersectionObserver 在 性能檢測 中也有應用場景。
比如昨天,我們講解的 前端埋點與監控最佳實踐:從基礎到全流程實現 里,就可以通過 IntersectionObserver 來完成 【曝光監測】的功能:
trackEvent 方法參考 前端埋點與監控最佳實踐:從基礎到全流程實現
// 處理元素可見性變化的回調函數
function handleIntersection(entries, observer) {
entries.forEach(entry => {
// 檢查元素是否進入視口
if (entry.isIntersecting) {
console.log('元素已進入視口:', entry.target);
// 調用自定義追蹤事件函數,記錄元素可見性
trackEvent('element_visible', { elementId: entry.target.id });
// 可選:停止觀察該元素(僅觸發一次)
observer.unobserve(entry.target);
}
});
}
// 創建 IntersectionObserver 實例
const observer = new IntersectionObserver(handleIntersection, {
root: null, // 使用視口作為容器
threshold: 0.5 // 當元素 50% 可見時觸發回調
});
// 選擇需要觀察的目標元素
const targetElement = document.getElementById('target');
observer.observe(targetElement);
// 示例追蹤事件函數
function trackEvent(eventType, details) {
console.log(`記錄事件: ${eventType}`, details);
// 在這里將追蹤數據發送到服務器或分析服務
}
MutationObserver
MutationObserver 主要 監聽 DOM 的動態變化(添加、刪除 等)。在 SPA 應用中,動態加載的場景下會非常有用。
比如,我們做一個評論提交的功能,當用戶提交一條新評論時,我們希望檢測到 DOM 變化并觸發相關操作:
<div id="comments-section">
<p>評論列表:</p>
<div id="comments">
<p>用戶1: 很棒的文章!</p>
</div>
</div>
<button onclick="addComment()">添加評論</button>
<script>
// 模擬添加評論
function addComment() {
const comment = document.createElement("p");
comment.textContent = `用戶${Date.now()}: 新的評論內容`;
document.getElementById("comments").appendChild(comment);
}
// MutationObserver 實例
const commentsSection = document.getElementById("comments");
const observer = new MutationObserver((mutationsList) => {
mutationsList.forEach((mutation) => {
if (mutation.type === 'childList') {
// 調用自定義追蹤事件函數,記錄元素可見性
trackEvent('element_update', { elementId: target.target.id });
}
});
});
// 觀察評論區的子節點變化
observer.observe(commentsSection, {
childList: true, // 監聽子節點變化
});
</script>