详细讲解js中的ResizeObserver

一、ResizeObserver 是什么?

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


二、为什么需要 ResizeObserver?

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

方法 缺点
window.resize 只能监听窗口大小变化,无法监听单个元素
MutationObserver 只能监听 DOM 结构变化,无法监听尺寸变化
定时器(setInterval 性能差,频繁触发,浪费资源
objectiframe 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 等高精度场景)

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


五、完整示例:监听一个 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 元素尺寸变化的"终极解决方案",性能高、用法简单、现代浏览器全支持,是响应式开发的利器。


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


相关推荐
EstherNi9 小时前
vue3仿照elementui样式的写法,并进行校验,并且有默认值的设置
javascript·elementui
BumBle9 小时前
Vue项目中实现路由守卫自动取消Pending请求
前端
gCode Teacher 格码致知9 小时前
Javascript提高:get和post等请求,对于汉字和空格信息进行编码的原则-由Deepseek产生
开发语言·前端·javascript·node.js·jquery
竹林8189 小时前
从ethers.js迁移到Viem:我在一个DeFi项目前端重构中踩过的坑
前端·javascript
像我这样帅的人丶你还9 小时前
从交稿到甩锅预防:AI 前端流水线
前端·ai编程
想想弹幕会怎么做9 小时前
如何构建一颗可交互的ui树?
前端
程序员陆业聪9 小时前
我见过的最反直觉的 Android 架构问题:UseCase 越多,项目越烂
前端
Arya_aa10 小时前
网络:前端向后端发送网络请求渲染在页面上,将EasyMock中的信息用前端vue框架编写代码,最终展示在浏览器
前端·vue.js
LlNingyu10 小时前
文艺复兴,什么是CSRF,常见形式(一)
前端·安全·web安全·csrf
晓131310 小时前
React篇——第三章 状态管理之 Redux 篇
前端·javascript·react.js