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

Angular:浏览器宽度变化时获取div宽度遇ExpressionChangedAfterItHasBeenCheckedError

解决Angular中ExpressionChangedAfterItHasBeenCheckedError问题(div宽度自适应场景)

问题根源

你遇到的ExpressionChangedAfterItHasBeenCheckedError,是因为ngAfterViewChecked钩子在Angular完成变更检测周期之后执行,此时修改coOffset并调用detectChanges(),会让Angular检测到属性值在检测周期结束后发生变化,触发严格模式下的错误。同时,每次视图检查都更新coOffset属于冗余操作,会造成不必要的性能损耗和循环触发。

解决方案

通过以下方式修复问题:

  • 移除ngAfterViewChecked中的逻辑,避免频繁触发变更检测
  • 用ResizeObserver监听容器自身尺寸变化,仅在宽度真的改变时更新coOffset
  • 将窗口resize和容器尺寸变化逻辑分离,用markForCheck()标记需要变更检测,而非强制触发检测

修改后的代码

test.component.ts

import { Component, ElementRef, ViewChild, ChangeDetectorRef, OnInit, OnDestroy } from '@angular/core';

@Component({
  selector: 'app-test',
  templateUrl: './test.component.html',
  styleUrls: ['./test.component.css']
})
export class TestComponent implements OnInit, OnDestroy {
  public coOffset: number;
  public winWidth: number;
  @ViewChild('myContainer') coRef: ElementRef;
  private resizeObserver: ResizeObserver;

  constructor(private cd: ChangeDetectorRef) { }

  ngOnInit(): void {
    this.winWidth = window.innerWidth;
    // 绑定窗口resize事件
    window.addEventListener('resize', this.onResize.bind(this));
  }

  ngAfterViewInit(): void {
    // 初始化容器宽度
    this.updateContainerOffset();
    // 监听容器自身尺寸变化
    this.resizeObserver = new ResizeObserver(() => {
      this.updateContainerOffset();
    });
    this.resizeObserver.observe(this.coRef.nativeElement);
  }

  onResize(): void {
    this.winWidth = window.innerWidth;
    // 标记组件需要变更检测,由Angular在下一周期处理
    this.cd.markForCheck();
  }

  private updateContainerOffset(): void {
    this.coOffset = this.coRef.nativeElement.offsetWidth;
    this.cd.markForCheck();
  }

  ngOnDestroy(): void {
    // 清理监听,防止内存泄漏
    window.removeEventListener('resize', this.onResize.bind(this));
    this.resizeObserver?.disconnect();
  }
}

test.component.html(修正li容器问题,可选)

<div style="display:inline" #myContainer>
  <ul>
    <li>...</li>
    <li>...</li>
    <ng-container *ngIf="coOffset <= winWidth;">
      <li>...</li>
      <li>...</li>
    </ng-container>
  </ul>
</div>

说明

  1. ResizeObserver:专门用于监听元素尺寸变化的API,相比依赖视图钩子更高效,仅在容器宽度实际改变时触发更新
  2. markForCheck():告诉Angular组件状态已变化,需要在下一次变更检测周期中检查,避免强制触发检测导致的循环问题
  3. 监听清理:组件销毁时移除窗口resize事件和ResizeObserver,防止内存泄漏

内容的提问来源于stack exchange,提问作者Lowterm

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.31 10:15:35