一、核心概念解析
1. 定义与用途
- ResizeObserver 是 JavaScript API,用于异步监听 Element 或 SVGElement 的尺寸变化。
- 核心作用:在元素尺寸(宽度、高度)发生变化时触发回调函数,适用于响应式布局、动态内容调整等场景。
2. 工作原理
- 异步回调:回调函数在浏览器布局/重绘流程后触发,避免阻塞主线程。
- 微任务调度 :通过
Promise.resolve().then()
机制执行回调,确保在 DOM 修改后、渲染前调用。
- 内部机制 :
- 浏览器在布局阶段检测元素尺寸变化。
- 使用
lastReportedSize
缓存尺寸,避免重复触发。
- 循环检测机制防止无限回调(如修改元素尺寸导致死循环)。
二、基础用法与API
1. 基本用法
javascript
复制代码
// 创建观察器实例
const observer = new ResizeObserver((entries) => {
for (const entry of entries) {
const width = entry.contentRect.width;
const height = entry.contentRect.height;
console.log(`元素尺寸变化: ${width}x${height}`);
}
});
// 观察目标元素
const target = document.getElementById('myElement');
observer.observe(target);
// 停止观察
observer.unobserve(target); // 停止观察单个元素
observer.disconnect(); // 停止所有观察
2. 回调函数参数
- entries :
ResizeObserverEntry
对象数组,每个对象包含:
target
:被观察的元素。
contentRect
:元素内容区域的尺寸(width
, height
, top
, left
等)。
borderBoxSize
(可选):元素的边框尺寸(部分浏览器支持)。
三、高级应用场景
1. 响应式布局
- 动态调整布局:根据容器尺寸切换布局模式(如栅格布局)。
javascript
复制代码
const container = document.querySelector('.container');
const observer = new ResizeObserver((entries) => {
const width = entries[0].contentRect.width;
container.classList.toggle('grid-layout', width > 600);
});
observer.observe(container);
2. 数据可视化(如ECharts)
javascript
复制代码
const chart = echarts.init(document.getElementById('chart'));
const observer = new ResizeObserver(() => {
chart.resize();
});
observer.observe(document.getElementById('chart'));
3. 富文本编辑器
javascript
复制代码
const editor = document.querySelector('.editor');
const observer = new ResizeObserver((entries) => {
const height = entries[0].contentRect.height;
editor.style.height = `${height}px`;
});
observer.observe(editor);
4. 拖放功能
javascript
复制代码
const dropZone = document.querySelector('.drop-zone');
const observer = new ResizeObserver((entries) => {
const width = entries[0].contentRect.width;
dropZone.style.padding = `${width / 10}px`;
});
observer.observe(dropZone);
四、性能优化技巧
1. 防抖与节流
javascript
复制代码
const debounce = (fn, delay = 100) => {
let timer;
return (...args) => {
clearTimeout(timer);
timer = setTimeout(() => fn(...args), delay);
};
};
const observer = new ResizeObserver(debounce((entries) => {
// 执行逻辑
}));
2. 全局唯一实例
javascript
复制代码
export const GlobalResizeObserver = (function() {
const observer = new ResizeObserver((entries) => {
// 处理所有观察的元素
});
return {
observe: (element, callback) => {
// 存储回调并观察元素
},
unobserve: (element) => {
// 移除观察
}
};
})();
3. 生命周期管理
javascript
复制代码
// Vue
onMounted(() => {
observer.observe(element);
});
onBeforeUnmount(() => {
observer.unobserve(element);
});
// React
useEffect(() => {
observer.observe(element);
return () => {
observer.unobserve(element);
};
}, []);
五、兼容性与Polyfill
1. 浏览器兼容性
- 支持情况:现代浏览器(Chrome 64+, Firefox 69+, Safari 13.1+, Edge 79+)全面支持。
- 旧版浏览器:IE 不支持,需使用 Polyfill。
2. Polyfill 方案
bash
复制代码
npm install resize-observer-polyfill
javascript
复制代码
import ResizeObserver from 'resize-observer-polyfill';
if (!window.ResizeObserver) {
window.ResizeObserver = ResizeObserver;
}
六、常见问题与解决方案
1. 无限回调问题
- 原因:回调中修改元素尺寸导致循环触发。
- 解决方案 :
- 避免在回调中直接修改元素尺寸。
- 使用防抖或节流控制回调频率。
2. 元素卸载后继续触发
- 原因:未正确解绑观察器。
- 解决方案 :
- 在组件卸载时调用
unobserve
或 disconnect
。
- 使用
beforeUnmount
(Vue)或 useEffect
清理函数(React)。
3. 性能瓶颈
- 原因:观察过多元素或回调逻辑复杂。
- 解决方案 :
- 仅观察必要元素。
- 优化回调逻辑,避免重计算或重渲染。
七、实际案例分析
1. 动态调整字体大小
html
复制代码
<div id="container" style="resize: both; width: 300px; height: 200px;">
<div id="content">内容区域</div>
</div>
<script>
const observer = new ResizeObserver((entries) => {
const width = entries[0].contentRect.width;
const content = document.getElementById('content');
content.style.fontSize = `${Math.min(width, 200) / 10}px`;
});
observer.observe(document.getElementById('container'));
</script>
2. 表格列自适应
javascript
复制代码
const table = document.querySelector('.responsive-table');
const observer = new ResizeObserver((entries) => {
const width = entries[0].contentRect.width;
const columns = document.querySelectorAll('.column');
columns.forEach(col => {
col.style.width = `${width / columns.length}px`;
});
});
observer.observe(table);
八、总结
- 核心优势 :精准监听元素尺寸变化,避免传统
resize
事件的局限性。
- 最佳实践 :
- 优先使用现代浏览器,必要时引入 Polyfill。
- 合理管理观察器实例,避免内存泄漏。
- 结合防抖、节流优化性能。
- 未来方向:随着浏览器支持完善,ResizeObserver 将成为响应式设计的核心工具之一。