You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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未触发回调。

解决方案

  1. 确保目标元素尺寸随视口变化
    给#root元素添加样式,保证它的尺寸会随视口方向切换而变化:

    #root {
      width: 100vw;
      height: 100vh;
      box-sizing: border-box;
      margin: 0;
      padding: 0;
    }
    
  2. 补充监听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);
          });
        });
      }
    }
    
  3. 避免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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.27 11:18:21