一、ResizeObserver 是什么?
ResizeObserver
是一个 JavaScript 内置 API ,用于 异步监听一个或多个 DOM 元素的尺寸变化(content-box 或 border-box) 。当元素的 内容区域(content rect) 发生变化时,它会触发回调函数,而 不需要等待浏览器重绘或滚动事件。
二、为什么需要 ResizeObserver?
在 ResizeObserver 出现之前,开发者通常使用以下方式监听元素尺寸变化:
方法 | 缺点 |
---|---|
window.resize |
只能监听窗口大小变化,无法监听单个元素 |
MutationObserver |
只能监听 DOM 结构变化,无法监听尺寸变化 |
定时器(setInterval ) |
性能差,频繁触发,浪费资源 |
object 或 iframe hack |
复杂、不优雅、兼容性差 |
ResizeObserver 的优势:
- ✅ 精准监听任意元素 的尺寸变化
- ✅ 高性能,浏览器内部优化,避免重排
- ✅ 异步触发,不会阻塞渲染
- ✅ 支持监听多个元素
三、基本用法
1. 创建观察者
js
const observer = new ResizeObserver(entries => {
for (const entry of entries) {
console.log('尺寸变化:', entry.target);
console.log('新尺寸:', entry.contentRect);
}
});
2. 监听元素
js
const box = document.querySelector('.box');
observer.observe(box);
3. 停止监听
js
observer.unobserve(box); // 停止监听某个元素
observer.disconnect(); // 停止监听所有元素
四、回调参数详解:ResizeObserverEntry
每个 entry
是一个 ResizeObserverEntry
对象,包含以下属性:
属性 | 类型 | 含义 |
---|---|---|
target |
Element | 被监听的 DOM 元素 |
contentRect |
DOMRectReadOnly | 内容区域的尺寸(不含 padding/border) |
borderBoxSize |
ResizeObserverSize[] | 边框盒子尺寸(含 padding/border) |
contentBoxSize |
ResizeObserverSize[] | 内容盒子尺寸(不含 padding/border) |
devicePixelContentBoxSize |
ResizeObserverSize[] | 物理像素级别的内容盒子尺寸(用于 Canvas 等高精度场景) |
⚠️ 注意:
borderBoxSize
和contentBoxSize
是 数组,因为未来可能支持多列布局。
五、完整示例:监听一个 div 的尺寸变化
html
<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. 避免在回调中修改尺寸
在回调中修改元素尺寸可能导致 无限循环,如下:
js
// ❌ 错误示例:无限循环
observer.observe(box);
observer.onResize = () => {
box.style.width = '300px'; // 又会触发回调
};
✅ 3. 使用 requestAnimationFrame
优化绘制
如果需要在回调中触发重绘(如 Canvas),建议配合 requestAnimationFrame
:
js
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:
bash
npm install @juggle/resize-observer
js
import { ResizeObserver } from '@juggle/resize-observer';
if (!window.ResizeObserver) {
window.ResizeObserver = ResizeObserver;
}
九、实际应用场景
场景 | 用法 |
---|---|
图表自适应 | ECharts、Canvas 图表随容器变化重绘 |
响应式布局 | 自定义组件根据尺寸调整内部布局 |
虚拟滚动 | 根据容器高度动态计算可视区域 |
广告容器 | 监听广告位尺寸变化,触发重新加载 |
拖拽缩放 | 监听用户拖拽后容器尺寸变化 |
十、总结一句话
ResizeObserver 是监听 DOM 元素尺寸变化的"终极解决方案",性能高、用法简单、现代浏览器全支持,是响应式开发的利器。