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>
说明
- ResizeObserver:专门用于监听元素尺寸变化的API,相比依赖视图钩子更高效,仅在容器宽度实际改变时触发更新
- markForCheck():告诉Angular组件状态已变化,需要在下一次变更检测周期中检查,避免强制触发检测导致的循环问题
- 监听清理:组件销毁时移除窗口resize事件和ResizeObserver,防止内存泄漏
内容的提问来源于stack exchange,提问作者Lowterm
相关产品推荐
相关产品推荐

