ResizeObserver用于监听元素content-box尺寸变化,需在元素挂载DOM后初始化,不支持伪元素、display:none或未渲染的Shadow DOM节点,回调中应避免修改盒模型属性以防无限循环。

ResizeObserver基本用法和初始化时机
ResizeObserver 是浏览器原生的尺寸监听 API,它不依赖轮询或事件冒泡,直接响应元素 content-box 尺寸变化。关键点在于:必须在目标元素已挂载到 DOM 后再实例化观察者,否则会静默失败。
- 初始化前确保元素存在,比如放在
DOMContentLoaded回调里,或 Vue 的mounted、React 的useEffect(() => {}, [])中 - 不支持伪元素、
display: none元素或未渲染的 Shadow DOM 内部节点 - 每次回调接收的
entries是ResizeObserverEntry[],每个 entry 的target是被观察元素,contentRect提供宽高、坐标等(注意不是getBoundingClientRect()) - 示例:
const ro = new ResizeObserver(entries => { for (const entry of entries) { console.log(entry.contentRect.width, entry.contentRect.height); } }); ro.observe(document.getElementById('my-box'));
为什么resize事件不能替代ResizeObserver
window.resize 只响应视口变化,对元素内部重排、Flex 布局收缩、CSS 动画导致的尺寸变更完全无感。而 ResizeObserver 能捕获由以下操作触发的尺寸变更:
- 父容器宽度变化(如侧边栏展开)
- 子元素增删导致的回流(如列表项动态加载)
- CSS
transform: scale()不触发,但width/height修改会 - 使用
display: flex+flex-grow时,兄弟元素尺寸变化也会触发当前元素的回调
常见误用是试图用 window.addEventListener('resize', ...) 监听某个卡片组件的宽度变化——这根本不会触发。
避免无限回调和性能陷阱
ResizeObserver 回调会在每次尺寸变更后立即执行,若你在回调中修改了被观察元素的样式(如根据宽度设置 font-size),可能再次触发尺寸变化,形成循环。
- 不要在回调中直接修改
target的盒模型属性(width、padding、display等) - 如需响应式调整,优先用 CSS(
@container查询或clamp()),其次用requestAnimationFrame节流更新 - 观察多个元素时,一个
ResizeObserver实例可复用,不要为每个元素新建实例 - 注意兼容性:IE 完全不支持,Safari 13.1+、Chrome 64+、Firefox 69+ 支持;需要兼容旧版时,可用
resize-observer-polyfill,但 polyfill 依赖轮询,精度和性能较差
与IntersectionObserver混用时的注意事项
两者常一起用于“进入视口且尺寸就绪”的场景(如懒加载图表)。但要注意:
-
ResizeObserver回调不保证元素可见,IntersectionObserver不保证尺寸稳定 - 若需二者都满足才执行逻辑,建议用标志位控制,而非嵌套观察(例如在
ResizeObserver回调里检查intersectionRatio > 0) - 不要在一个回调里同时调用
unobserve()和observe(),可能导致丢失中间状态 - 多次调用
observe()同一元素是安全的,但重复调用unobserve()会报错(ResizeObserver.unobserve: element is not observed)
真正容易被忽略的是:当元素被 display: none 或从 DOM 移除时,ResizeObserver 不会抛错,也不会再触发回调——你得自己管理生命周期。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











