2023-07-10 22:10:08
在 JavaScript 中监听元素尺寸变化,主要有三种方案:ResizeObserver、MutationObserver 和传统事件监听(如 window.onresize)。以下是具体实现方法及适用场景:
1. ResizeObserver(现代浏览器首选)ResizeObserver 是专门为监听元素尺寸变化设计的 API,性能高效且 API 简洁。

基本用法:
const element = document.getElementById('yourElement');const resizeObserver = new ResizeObserver(entries => { for (let entry of entries) { const width = entry.contentRect.width; const height = entry.contentRect.height; console.log(`Element's new size: width=${width}, height=${height}`); }});resizeObserver.observe(element);// 停止监听// resizeObserver.unobserve(element);// resizeObserver.disconnect();优势:
高效:仅在元素尺寸变化时触发回调。
简单易用:API 设计直观。
针对性强:专为监听元素尺寸变化设计。
兼容性:
需考虑浏览器兼容性(可通过
不支持旧版浏览器时需使用备选方案。
MutationObserver 可监听 DOM 属性变化,通过过滤 style 属性变化间接实现尺寸监听。
基本用法:
const element = document.getElementById('yourElement');const observer = new MutationObserver(mutations => { mutations.forEach(mutation => { if (mutation.type === 'attributes' && mutation.attributeName === 'style') { const width = element.offsetWidth; const height = element.offsetHeight; console.log(`Element's size changed: width=${width}, height=${height}`); } });});observer.observe(element, { attributes: true, attributeFilter: ['style'] // 仅监听 style 属性变化});// 停止监听// observer.disconnect();缺点:
性能较差:需监听所有属性变化后过滤。
复杂性高:使用逻辑比 ResizeObserver 复杂。
适用场景:
需兼容旧浏览器且对性能要求不高。
需同时监听其他 DOM 变化(如属性、子节点)。
通过 window.onresize 监听窗口大小变化,间接判断元素尺寸变化。
基本用法:
window.onresize = () => { const element = document.getElementById('yourElement'); const width = element.offsetWidth; const height = element.offsetHeight; console.log(`Element's size changed: width=${width}, height=${height}`);};缺点:
性能问题:每次窗口变化均触发回调,即使元素尺寸未变。
全局性:监听窗口而非特定元素。
适用场景:
需兼容所有浏览器。
仅需在窗口变化时执行全局操作。
若元素尺寸变化频繁,可通过节流(throttle)或防抖(debounce)优化性能:
节流示例:
function throttle(func, delay) { let timeoutId; let lastExecTime = 0; return function(...args) { const currentTime = Date.now(); if (!timeoutId) { if (currentTime - lastExecTime >= delay) { func.apply(this, args); lastExecTime = currentTime; } else { timeoutId = setTimeout(() => { func.apply(this, args); timeoutId = null; lastExecTime = Date.now(); }, delay - (currentTime - lastExecTime)); } } };}const throttledResizeObserver = new ResizeObserver(throttle(entries => { console.log("Throttled resize event");}, 200)); // 200ms 节流防抖示例:
function debounce(func, delay) { let timeoutId; return function(...args) { clearTimeout(timeoutId); timeoutId = setTimeout(() => { func.apply(this, args); }, delay); };}const debouncedResizeObserver = new ResizeObserver(debounce(entries => { console.log("Debounced resize event");}, 200)); // 200ms 防抖