ResizeObserver回调在设备两次旋转后不再触发的技术求助
问题:ResizeObserver仅首次触发设备方向切换回调,后续失效
- 场景:通过ResizeObserver API监听设备方向切换与全屏模式变化,Observer已成功注册
- 异常表现:首次从竖屏切换到横屏时回调正常触发,但后续横竖屏切换时回调不再执行;可确认Observer实例仍存活,因为全屏模式变化的resize事件能正常监听
- 预期行为:创建ResizeObserver实例后,应监听所有resize、方向切换、全屏模式变化事件
- 实际行为:仅首次捕获方向变化事件,后续不再监听,但其他resize事件正常
实现代码
type TCallback = { [key in string]: (_: ResizeObserverEntry)=>void } export class ContainerObserver { private static instanceCache: ContainerObserver ; private observerInstance: ResizeObserver; private resizeCallbacks: { [key in string]: (_: ResizeObserverEntry) => void; } = {}; private RootContainer: HTMLDivElement; private constructor() { this.RootContainer = document.querySelector("#root")!; if (this.RootContainer) { this.observerInstance = new ResizeObserver((entries) => { const relativeTo = entries?.[0]; Object.values(this.resizeCallbacks).forEach((callback) => { callback(relativeTo); }); }); this.observerInstance.observe(this.RootContainer); } } public static get instance(): ContainerObserver { if (!ContainerObserver.instanceCache) { ContainerObserver.instanceCache = new ContainerObserver(); } return ContainerObserver.instanceCache; } addCallbackObserver(callback:TCallback) { this.resizeCallbacks = { ...this.resizeCallbacks, ...callback }; console.log({callbacks: this.resizeCallbacks}) } getInstance(){ return this.observerInstance } // 停止监听元素 unobserve() { this.observerInstance.unobserve(this.RootContainer); } }
类的使用方式
ContainerObserver.instance.addCallbackObserver({ handleResize });
问题分析与解决方案
核心原因
ResizeObserver的触发依赖于目标元素的实际尺寸变化,部分场景下设备方向切换后,#root元素的尺寸变化可能被浏览器优化抑制,或者元素本身的样式设置导致尺寸未随视口同步变化,进而导致后续方向切换时ResizeObserver未触发回调。
解决方案
确保目标元素尺寸随视口变化
给#root元素添加样式,保证它的尺寸会随视口方向切换而变化:#root { width: 100vw; height: 100vh; box-sizing: border-box; margin: 0; padding: 0; }补充监听
orientationchange事件作为兜底
在ContainerObserver的构造函数中添加orientationchange事件监听,强制触发回调逻辑,避免ResizeObserver漏触发:private constructor() { this.RootContainer = document.querySelector("#root")!; if (this.RootContainer) { // 原ResizeObserver逻辑 this.observerInstance = new ResizeObserver((entries) => { const relativeTo = entries?.[0]; Object.values(this.resizeCallbacks).forEach((callback) => { callback(relativeTo); }); }); this.observerInstance.observe(this.RootContainer); // 新增方向切换监听 window.addEventListener('orientationchange', () => { // 手动获取元素尺寸,触发回调 const entry = { target: this.RootContainer, contentRect: this.RootContainer.getBoundingClientRect() } as ResizeObserverEntry; Object.values(this.resizeCallbacks).forEach((callback) => { callback(entry); }); }); } }避免ResizeObserver的回调抑制
部分浏览器会对连续的尺寸变化合并触发ResizeObserver,可在回调中通过requestAnimationFrame确保回调执行:this.observerInstance = new ResizeObserver((entries) => { requestAnimationFrame(() => { const relativeTo = entries?.[0]; Object.values(this.resizeCallbacks).forEach((callback) => { callback(relativeTo); }); }); });
内容的提问来源于stack exchange,提问作者TANMAY RATHOD
相关产品推荐
相关产品推荐

