返回

MutationObserver和IntersectionObserver:揭秘最易被忽视却必不可少的API

前端

前言

在日常开发中,我们通常会遇到元素的监听需求,不管是元素位置的监听还是元素内容的监听。如果没有原生API的支持,我们通常会想尽一切办法去实现它们,而且各类开源的解决方案也层出不穷。那有没有使用方便、功能强大的API直接支持这些功能呢?答案是肯定的,MutationObserver和IntersectionObserver就是两颗遗珠。这两个API可以轻松实现元素监听的需求,而且用法简单、兼容性良好。本文将详细介绍这两个API的用法和应用场景,帮助开发者们在日常开发中游刃有余。

MutationObserver

MutationObserver是一个可以监听DOM元素变化的API。它可以监听元素的属性变化、子元素的变化以及文本内容的变化。MutationObserver的用法非常简单,首先我们需要创建一个新的MutationObserver对象,然后将要监听的元素和监听的类型传递给这个对象。接下来,我们需要定义一个回调函数,当元素发生变化时,这个回调函数就会被调用。

const observer = new MutationObserver((mutations, observer) => {
  for (const mutation of mutations) {
    console.log(mutation);
  }
});

observer.observe(document.documentElement, {
  childList: true,
  attributes: true,
  characterData: true
});

上面的代码创建一个MutationObserver对象,并监听document.documentElement元素的所有变化。当元素发生变化时,控制台将会输出变化的详细信息。

MutationObserver可以监听的类型有:

  • childList:监听元素的子元素的变化。
  • attributes:监听元素的属性的变化。
  • characterData:监听元素的文本内容的变化。

MutationObserver是一个非常强大的API,它可以用来创建各种各样的应用程序。例如,我们可以使用MutationObserver来实现表单验证、图像加载和无限滚动。

表单验证

使用MutationObserver可以轻松实现表单验证。我们可以监听表单元素的变化,并在用户提交表单时检查表单是否有效。

const form = document.getElementById('form');

const observer = new MutationObserver((mutations, observer) => {
  for (const mutation of mutations) {
    if (mutation.target.tagName === 'INPUT') {
      validateInput(mutation.target);
    }
  }
});

observer.observe(form, {
  childList: true,
  attributes: true,
  characterData: true
});

function validateInput(input) {
  const value = input.value;
  if (value === '') {
    input.classList.add('invalid');
  } else {
    input.classList.remove('invalid');
  }
}

上面的代码创建一个MutationObserver对象,并监听表单的所有变化。当表单元素发生变化时,validateInput()函数会被调用,该函数会检查输入元素是否有效。如果输入元素无效,则会添加一个invalid类到该元素上。

图像加载

MutationObserver可以用来监听图像的加载。我们可以监听图像的src属性的变化,并在图像加载完成后执行某些操作。

const images = document.querySelectorAll('img');

const observer = new MutationObserver((mutations, observer) => {
  for (const mutation of mutations) {
    if (mutation.target.tagName === 'IMG' && mutation.type === 'attributes') {
      if (mutation.attributeName === 'src') {
        imageLoaded(mutation.target);
      }
    }
  }
});

observer.observe(document.documentElement, {
  childList: true,
  attributes: true,
  characterData: true,
  subtree: true
});

function imageLoaded(image) {
  console.log(image.src + ' has been loaded');
}

上面的代码创建一个MutationObserver对象,并监听document.documentElement元素的所有变化。当图像的src属性发生变化时,imageLoaded()函数会被调用,该函数会输出图像的src属性值。

无限滚动

MutationObserver可以用来实现无限滚动。我们可以监听页面底部的元素的变化,并在用户滚动到页面底部时加载更多内容。

const loadMoreButton = document.getElementById('load-more');

const observer = new MutationObserver((mutations, observer) => {
  for (const mutation of mutations) {
    if (mutation.target === loadMoreButton) {
      loadMoreContent();
    }
  }
});

observer.observe(loadMoreButton, {
  attributes: true
});

function loadMoreContent() {
  // 加载更多内容
}

上面的代码创建一个MutationObserver对象,并监听loadMoreButton元素的属性变化。当loadMoreButton元素的属性发生变化时,loadMoreContent()函数会被调用,该函数会加载更多内容。

IntersectionObserver

IntersectionObserver是一个可以监听元素位置变化的API。它可以监听元素是否进入或离开视口。IntersectionObserver的用法非常简单,首先我们需要创建一个新的IntersectionObserver对象,然后将要监听的元素和监听的类型传递给这个对象。接下来,我们需要定义一个回调函数,当元素进入或离开视口时,这个回调函数就会被调用。

const observer = new IntersectionObserver((entries, observer) => {
  for (const entry of entries) {
    console.log(entry);
  }
});

observer.observe(document.documentElement);

上面的代码创建一个IntersectionObserver对象,并监听document.documentElement元素的位置变化。当元素进入或离开视口时,控制台将会输出元素的详细信息。

IntersectionObserver可以监听的类型有:

  • intersectionRatio:监听元素与视口的相交比例。
  • rootMargin:监听元素与视口的相交比例的偏移量。
  • threshold:监听元素与视口的相交比例的阈值。

IntersectionObserver是一个非常强大的API,它可以用来创建各种各样的应用程序。例如,我们可以使用IntersectionObserver来实现懒加载、视差滚动和无限滚动。

懒加载

IntersectionObserver可以用来实现懒加载。我们可以监听图像的进入视口,并在图像进入视口时加载图像。

const images = document.querySelectorAll('img');

const observer = new IntersectionObserver((entries, observer) => {
  for (const entry of entries) {
    if (entry.isIntersecting) {
      loadImage(entry.target);
    }
  }
});

observer.observe(document.documentElement);

function loadImage(image) {
  image.src = image.dataset.src;
}

上面的代码创建一个IntersectionObserver对象,并监听document.documentElement元素的所有变化。当图像进入视口时,loadImage()函数会被调用,该函数会加载图像。

视差滚动

IntersectionObserver可以用来实现视差滚动。我们可以监听元素的进入视口,并在元素进入视口时改变元素的样式。

const elements = document.querySelectorAll('.parallax');

const observer = new IntersectionObserver((entries, observer) => {
  for (const entry of entries) {
    if (entry.isIntersecting) {
      element.classList.add('parallax-active');
    } else {
      element.classList.remove('parallax-active');
    }
  }
});

observer.observe(document.documentElement);

上面的代码创建一个IntersectionObserver对象,并监听document.documentElement元素的所有变化。当元素进入视口时,element.classList.add('parallax-active')会被调用,该函数会为元素添加一个parallax-active类。当元素离开视口时,element.classList.remove('parallax-active')会被调用,该函数会移除元素的parallax-active类。

无限滚动

IntersectionObserver可以用来实现无限滚动。我们可以监听页面底部的元素的进入视口,并在用户滚动到页面底部时加载更多内容。

const loadMoreButton = document.getElementById('load-more');

const observer = new IntersectionObserver((entries, observer) => {
  for (const entry of entries) {
    if (entry.isIntersecting) {
      loadMoreContent();
    }
  }
});

observer.observe(loadMoreButton);

function loadMoreContent() {
  // 加载更多内容
}

上面的代码创建一个IntersectionObserver对象,并监听loadMoreButton元素的位置变化。当loadMoreButton元素进入视口时,loadMoreContent()函数会被调用,该函数会加载更多内容。

结语

MutationObserver和IntersectionObserver是两个非常强大的API,它们可以用来创建各种各样的应用程序。这些API的使用非常简单,而且兼容性良好。希望本文能够帮助开发者们更好地理解和使用这两个API。