面试官:MutationObserver与IntersectionObserver 傻傻分不清楚?

开发 前端
MutationObserver 主要 监听 DOM 的动态变化(添加、删除 等)。在 SPA 应用中,动态加载的场景下会非常有用。

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>


责任编辑:武晓燕 来源: 程序员Sunday
相关推荐

2021-03-10 08:56:37

Zookeeper

2021-07-27 07:31:16

JavaArrayList数组

2022-05-15 21:52:04

typeTypeScriptinterface

2024-02-29 09:08:56

Encoding算法加密

2020-10-30 08:20:04

SD卡TF卡存储

2018-12-17 12:30:05

Kubernetes存储存储卷

2021-11-09 06:01:35

前端JITAOT

2018-05-22 16:24:20

HashMapJavaJDK

2020-03-03 17:35:09

Full GCMinor

2023-02-27 15:46:19

数据元元数据

2023-09-03 21:18:07

Python编程语言

2021-02-08 23:47:51

文件存储块存储对象存储

2022-02-25 09:14:33

类变量共享实例变量

2016-11-04 12:51:46

Unix网络IO 模型

2023-04-11 15:57:49

JavaScriptCSSHTML

2020-11-11 07:32:18

MySQL InnoDB 存储

2021-01-13 08:10:26

接口IEnumeratorIEnumerable

2021-02-14 22:33:23

Java字符字段

2019-11-21 14:22:12

WiFiWLAN区别

2021-12-29 07:34:40

Filter CSS backdrop-fi
点赞
收藏

51CTO技术栈公众号