如何优雅的监听dom的变化(尺寸)
ResizeObserver的用法
- 介绍
- ResizeObserver 是什么?
- 三步走:最小可运行例子
- 生命周期与内存管理
- 回调参数详解
- 在 Vue3 中的两种姿势
- 实例的observe方法是否可以传入多个参数
介绍
ResizeObserver 是什么?
ResizeObserve
浏览器原生 API,用来「异步」监听某个(或某些)DOM 元素的内容盒 / 边框盒尺寸变化
替代传统的 window.resize + getBoundingClientRect 轮询,避免全局事件、减少重排,性能更优
三步走:最小可运行例子
<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>Document</title>
</head>
<body><div id="box" style="resize:both;overflow:hidden;border:1px solid">拖拽右下角改变我<div id="box1" style="resize:both;overflow:hidden;border:1px solid;margin: 35px;">拖拽右下角改变我</div></div><script>const box = document.getElementById('box');const box1 = document.getElementById('box1');// 1️⃣ 创建观察者const observer = new ResizeObserver(entries => {for (const entry of entries) {console.log('entry',entry)const { width, height } = entry.contentRect; // 内容区尺寸console.log(`新尺寸 ${width}×${height}`);}});// 2️⃣ 开始观察observer.observe(box);observer.observe(box1);// 3️⃣ 随时可停止// observer.unobserve(box); // 单个// observer.disconnect(); // 全部</script>
</body>
</html>
生命周期与内存管理
• observe() 后立即生效,元素被移除时会自动停止,不会泄漏。
• 组件卸载前手动 disconnect() / unobserve() 可提前释放引用(尤其 SPA)。
回调参数详解
每个 entry(ResizeObserverEntry)包含:
属性 | 含义 | 兼容性 |
---|---|---|
target | 被观察的节点 | 100% |
contentRect | DOMRectReadOnly,内容区宽高 | 100% |
borderBoxSize | {inlineSize, blockSize} 数组 | 部分浏览器 |
contentBoxSize | 同上,内容盒 | 同上 |
在 Vue3 中的两种姿势
vue3代码中实际运行
import { onMounted, onUnmounted, ref } from 'vue'const myDiv = ref(null)
const divWidth = ref(0)
let observer = nullonMounted(() => {if (myDiv.value) {observer = new ResizeObserver(entries => {divWidth.value = entries[0].contentRect.width})observer.observe(myDiv.value)}
})onUnmounted(() => {observer?.disconnect()
})
<template><div ref="root" class="chart-container"></div>
</template><script setup>
import { ref, onMounted, onBeforeUnmount } from 'vue'const root = ref(null)
let observer = nullonMounted(() => {observer = new ResizeObserver(entries => {const { width, height } = entries[0].contentRect// 调用 echarts.resize({width, height}) 等})observer.observe(root.value)
})onBeforeUnmount(() => observer?.disconnect())
</script>
使用 @vueuse/core 的 useResizeObserver(更简洁)
import { useResizeObserver } from '@vueuse/core'const { width, height } = useResizeObserver(root)
实例的observe方法是否可以传入多个参数
不可以。
ResizeObserver.prototype.observe(target, options?) 只接受两个参数:
target(必需):要监听的单个 DOM 元素。
options(可选):一个配置对象,如 { box: ‘border-box’ },用于指定观察哪个盒模型。
因此:
❌ 不能一次传入多个元素;想监听 N 个节点,就要对每个节点都调用一次 observe()。
✅ 同一个 ResizeObserver 实例可以多次调用 observe(),把所有需要监听的元素都注册进去;在回调里通过 entry.target 区分来源即可
const obs = new ResizeObserver(entries => {entries.forEach(entry => {console.log(entry.target, entry.contentRect);});
});// 分别注册 3 个元素
obs.observe(document.querySelector('#a'));
obs.observe(document.querySelector('#b'));
obs.observe(document.querySelector('#c'));