跳到主要内容

DOM 观察者

ResizeObserver 作用是什么

答案

核心概念

ResizeObserver 是一种原生 Web API,用于高效、精准地监听 DOM 元素尺寸的变化(宽高等),无论变化来源于内容、样式还是窗口调整。它能在元素尺寸发生变化时自动回调,适合响应式布局、动态组件等场景。

详细解释

  • 传统的 window.resize 事件只能监听窗口变化,无法直接感知单个元素的尺寸变化,且需轮询或定时器,效率低。
  • ResizeObserver 通过回调机制,能实时捕获元素尺寸变化,避免性能浪费和延迟。
  • 支持同时监听多个元素,回调参数为变化元素的列表,可批量处理。

代码示例

const target = document.querySelector('.resizable')
const observer = new ResizeObserver(entries => {
for (const entry of entries) {
// entry.contentRect 包含新尺寸
console.log('size:', entry.contentRect.width, entry.contentRect.height)
}
})
observer.observe(target)

常见误区

  • 只监听元素本身的尺寸变化,不会响应子元素内容变化,除非影响父元素尺寸。
  • 回调是异步批量触发,避免在回调中频繁操作 DOM。
  • 兼容性较好,但 IE 不支持,需注意降级处理。
提示

推荐在响应式组件、图表自适应、弹窗等场景优先使用 ResizeObserver,替代定时器和 resize 事件监听。

延伸阅读

IntersectionObserver api?

IntersectionObserver API 是现代浏览器提供的一个强大的 API,用于性能友好地跟踪元素是否进入、离开或穿过另一个元素(通常是视口)的边界。这个 API 特别适用于执行懒加载、实现无限滚动、检测广告展示等功能,因为它避免了使用传统的滚动事件监听,后者可能会因频繁的计算和 DOM 操作导致性能问题。

如何使用 IntersectionObserver

  1. 创建一个IntersectionObserver实例: 创建一个IntersectionObserver的新实例,你需要提供一个回调函数,该函数会在目标元素与其祖先或视口交叉状态变化时被调用。此外,你还可以提供一个选项对象来定义观察的具体条件。

  2. 观察元素: 使用observe方法来指定一直观察的目标 DOM 元素。代表当这个 DOM 元素的显示与否达到某个条件时,你的回调函数将会被执行。

  3. 处理交叉事件: 当观察的元素进入或离开另一个元素时,为创建IntersectionObserver实例时指定的回调函数将会被调用。

  4. 停止观察: 使用unobserve方法可以停止观察特定元素。如果你已完成观察任务,使用disconnect方法将停止所有观察,释放资源。

示例代码

以下是如何使用IntersectionObserver的示例:

// 创建一个回调函数,当观察的元素交叉进入或离开另一个元素时,该函数会被触发
const callback = (entries, observer) => {
entries.forEach((entry) => {
// 检查entry.isIntersecting属性
if (entry.isIntersecting) {
// 元素已进入视口
console.log('Element is in the viewport!')
} else {
// 元素已离开视口
console.log('Element is out of the viewport!')
}
})
}

// 创建IntersectionObserver实例
const options = {
root: null, // 使用浏览器视口作为根
rootMargin: '0px', // 根的外边距,类似于CSS的margin
threshold: 1.0 // 目标完全可见时触发回调
}

const observer = new IntersectionObserver(callback, options)

// 开始观察目标元素
const target = document.getElementById('yourTargetElementId')
observer.observe(target)

// 停止观察目标元素
// observer.unobserve(target);

在这个示例中,当目标元素(idyourTargetElementId的元素)完全进入视口时,回调函数将被触发。root设为null意味着默认使用视口作为参照根元素。rootMargin设为0px表示根和目标的边界框触碰时回调就会被触发。threshold1.0,表示目标完全可见时回调会被触发。

注意事项

  • IntersectionObserver在性能上比传统的滚动事件检测方式有显著优势,因为它不依赖于JavaScript在主线程上的事件循环。
  • 使用时应当注意浏览器兼容性问题,对于不支持该 API 的旧浏览器,可能需要添加 polyfill 以保证功能的实现。

参考文档

MutationObserver

MutationObserver 是一种能够响应 DOM 树变动的 Web API,它可以监听几乎所有类型的 DOM 变动,比如元素被添加、删除或修改。你可以通过它执行 callback 来应对这些变化。

下面是 MutationObserver 的基本用法:

创建 MutationObserver 实例

const observer = new MutationObserver(callback)

配置观察者

你可以指定要观察的 DOM 变动的类型和具体的目标节点:

const config = {
attributes: true, // 观察属性变动
childList: true, // 观察子列表变动
subtree: true // 观察后代节点
}

observer.observe(targetNode, config)

这里的 callback 是一个在观察到变动时执行的函数,它有两个参数:mutationsList 是一个变动列表,observer 是观察者实例。

回调函数

MutationCallback 函数会被调用,它有两个参数:

  1. mutationsList:一个 MutationRecord 对象的数组,每个对象都描述了一个变动。
  2. observer:触发通知的 MutationObserver 实例。
function callback (mutationsList) {
for (const mutation of mutationsList) {
if (mutation.type === 'childList') {
console.log('A child node has been added or removed.')
} else if (mutation.type === 'attributes') {
console.log(`The ${mutation.attributeName} attribute was modified.`)
}
}
}

停止观察

你可以通过调用 disconnect 方法来停止观察:

observer.disconnect()

这将停止观察并且清除之前的记录。

注意

  • 使用 MutationObserver 应该谨慎,因为它可能对页面性能产生影响,尤其是在观察大型 DOM 树或频繁变动时。
  • 尽量不要过度使用 MutationObserver 或过度指定需要它观察的变动种类和节点。

比如,如果你只想监听某个特定属性的变动,那么就不应该打开 childList 或者 attributes(如果不需要观察它们)。

MutationObserver 非常适用于响应 DOM 的动态变动来执行特定的 JavaScript 代码,而且是现代前端开发中的一个重要工具。在使用它时,考虑使用最严格的选项来优化性能并减少不必要的性能损耗。

使用场景

  1. 埋点

PerformanceObserver 如何测量页面性能

PerformanceObserver API 是一个强大的浏览器接口,允许开发者订阅性能相关的事件,实时收集和分析用户当前浏览器会话中的性能数据。这个 API 是 Web 性能监测工具箱的一部分,与 window.performance 对象紧密协作,后者提供了对网页性能数据的访问。PerformanceObserver 允许应用异步监听性能测量事件,而不需要定时检查 window.performance 的条目。

核心功能

  • 实时性能数据收集:随着网页生命周期中各种事件的触发,PerformanceObserver 支持实时捕获和处理性能数据条目。
  • 减少资源消耗:与轮询 window.performance 对象相比,使用 PerformanceObserver 可以降低资源消耗,并提供更及时的数据收集。
  • 灵活的数据订阅模型:可以指定订阅一个或多个特定类型的性能条目,根据需要接收相关数据。

主要方法

  • observe():开始观察一个或多个特定类型的性能条目。通过指定条目类型,应用可以订阅感兴趣的性能事件。
  • disconnect():停止观察性能数据。这可以释放相关资源,并停止进一步的回调执行。

使用示例

下面的例子展示了如何使用 PerformanceObserver 来监听首次内容绘制 (First Contentful Paint, FCP) 和最大内容绘制 (Largest Contentful Paint, LCP) 的性能指标。

const perfObserver = new PerformanceObserver((entryList) => {
for (const entry of entryList.getEntries()) {
if (entry.name === 'first-contentful-paint') {
console.log('FCP:', entry.startTime)
} else if (entry.name === 'largest-contentful-paint') {
console.log('LCP:', entry.startTime)
}
}
})

perfObserver.observe({ type: 'paint', buffered: true })

在这个例子中,perfObserver 被配置为监听包含 FCP 和 LCP 的 paint 类型的性能条目。当这些指标被记录到性能时间线上时,回调函数将被执行,并可以对这些数据进行进一步的处理,比如打印在控制台或发送到服务器。

注意事项

  • PerformanceObserver API 的支持程度取决于浏览器和浏览器版本。为了最好地利用这一 API,推荐检查目标用户群体最常用浏览器的兼容性。
  • 合理使用 disconnect() 方法来停止数据的观察(特别是在单页应用中或在不再需要收集数据时)有助于保持应用的性能。
  • buffered 选项允许接收到观察者激活之前已经记录的性能条目,这在页面加载阶段尤其有用。

通过 PerformanceObserver,开发者可以精细控制性能数据的收集过程,有效监控和分析网页性能,从而提升用户体验。

48%