详细讲解js中的ResizeObserver

240 阅读3分钟

一、ResizeObserver 是什么?

ResizeObserver 是一个 JavaScript 内置 API,用于 异步监听一个或多个 DOM 元素的尺寸变化(content-box 或 border-box)。当元素的 内容区域(content rect) 发生变化时,它会触发回调函数,而 不需要等待浏览器重绘或滚动事件


二、为什么需要 ResizeObserver?

在 ResizeObserver 出现之前,开发者通常使用以下方式监听元素尺寸变化:

方法缺点
window.resize只能监听窗口大小变化,无法监听单个元素
MutationObserver只能监听 DOM 结构变化,无法监听尺寸变化
定时器(setInterval性能差,频繁触发,浪费资源
objectiframe hack复杂、不优雅、兼容性差

ResizeObserver 的优势:

  • 精准监听任意元素 的尺寸变化
  • 高性能,浏览器内部优化,避免重排
  • 异步触发,不会阻塞渲染
  • 支持监听多个元素

三、基本用法

1. 创建观察者

const observer = new ResizeObserver(entries => {
  for (const entry of entries) {
    console.log('尺寸变化:', entry.target);
    console.log('新尺寸:', entry.contentRect);
  }
});

2. 监听元素

const box = document.querySelector('.box');
observer.observe(box);

3. 停止监听

observer.unobserve(box);   // 停止监听某个元素
observer.disconnect();     // 停止监听所有元素

四、回调参数详解:ResizeObserverEntry

每个 entry 是一个 ResizeObserverEntry 对象,包含以下属性:

属性类型含义
targetElement被监听的 DOM 元素
contentRectDOMRectReadOnly内容区域的尺寸(不含 padding/border)
borderBoxSizeResizeObserverSize[]边框盒子尺寸(含 padding/border)
contentBoxSizeResizeObserverSize[]内容盒子尺寸(不含 padding/border)
devicePixelContentBoxSizeResizeObserverSize[]物理像素级别的内容盒子尺寸(用于 Canvas 等高精度场景)

⚠️ 注意:borderBoxSizecontentBoxSize数组,因为未来可能支持多列布局。


五、完整示例:监听一个 div 的尺寸变化

<div class="box" style="width: 200px; height: 100px; background: lightblue;"></div>
<button onclick="changeSize()">改变尺寸</button>

<script>
  const box = document.querySelector('.box');

  const observer = new ResizeObserver(entries => {
    for (const entry of entries) {
      const { width, height } = entry.contentRect;
      console.log(`新尺寸: ${width}x${height}`);
    }
  });

  observer.observe(box);

  function changeSize() {
    box.style.width = Math.random() * 300 + 'px';
    box.style.height = Math.random() * 200 + 'px';
  }
</script>

六、性能优化与注意事项

✅ 1. 防抖与节流不需要

ResizeObserver 本身已经由浏览器 异步批量处理不需要手动防抖或节流

✅ 2. 避免在回调中修改尺寸

在回调中修改元素尺寸可能导致 无限循环,如下:

// ❌ 错误示例:无限循环
observer.observe(box);
observer.onResize = () => {
  box.style.width = '300px'; // 又会触发回调
};

✅ 3. 使用 requestAnimationFrame 优化绘制

如果需要在回调中触发重绘(如 Canvas),建议配合 requestAnimationFrame

let rafId;
observer.observe(canvas);
observer.onResize = () => {
  cancelAnimationFrame(rafId);
  rafId = requestAnimationFrame(() => {
    redrawCanvas();
  });
};

七、兼容性(2025年更新)

浏览器支持情况
Chrome✅ 64+(2018年)
Firefox✅ 69+
Safari✅ 13.1+
Edge✅ 79+(Chromium 内核)
IE❌ 不支持

✅ 现代浏览器已全面支持,可放心使用


八、Polyfill(兼容旧浏览器)

使用 @juggle/resize-observer polyfill:

npm install @juggle/resize-observer
import { ResizeObserver } from '@juggle/resize-observer';

if (!window.ResizeObserver) {
  window.ResizeObserver = ResizeObserver;
}

九、实际应用场景

场景用法
图表自适应ECharts、Canvas 图表随容器变化重绘
响应式布局自定义组件根据尺寸调整内部布局
虚拟滚动根据容器高度动态计算可视区域
广告容器监听广告位尺寸变化,触发重新加载
拖拽缩放监听用户拖拽后容器尺寸变化

十、总结一句话

ResizeObserver 是监听 DOM 元素尺寸变化的“终极解决方案”,性能高、用法简单、现代浏览器全支持,是响应式开发的利器。


十一、进阶阅读(官方文档)