解决NGUniversal中window is not defined错误
Angular SSR 解决
window is not defined 问题(Angular 16.2.12 + ng-universal) 针对你遇到的服务端渲染时window对象未定义的问题,提供以下几种实用解决方式:
方法1:通过PLATFORM_ID判断环境初始化
利用Angular提供的PLATFORM_ID标识当前运行环境,仅在浏览器端初始化滚动监听:
import { Component, Inject, PLATFORM_ID } from '@angular/core'; import { isPlatformBrowser } from '@angular/common'; import { fromEvent, Observable } from 'rxjs'; @Component({ selector: 'app-root', templateUrl: './app.component.html', styleUrls: ['./app.component.css'] }) export class AppComponent { private ScrollWatcher!: Observable<Event>; constructor(@Inject(PLATFORM_ID) private platformId: Object) { // 仅在浏览器环境下执行window相关逻辑 if (isPlatformBrowser(this.platformId)) { this.ScrollWatcher = fromEvent(window, 'scroll'); // 这里添加滚动事件的订阅逻辑 // this.ScrollWatcher.subscribe(event => { /* 处理滚动 */ }); } } }
方法2:使用浏览器专属生命周期钩子
ngAfterViewInit是仅在浏览器端渲染完成后才会触发的生命周期钩子,SSR过程不会执行,可安全访问window:
import { Component, AfterViewInit } from '@angular/core'; import { fromEvent, Observable } from 'rxjs'; @Component({ selector: 'app-root', templateUrl: './app.component.html', styleUrls: ['./app.component.css'] }) export class AppComponent implements AfterViewInit { private ScrollWatcher!: Observable<Event>; ngAfterViewInit(): void { this.ScrollWatcher = fromEvent(window, 'scroll'); // 添加滚动事件处理逻辑 } }
方法3:结合DOCUMENT注入规范访问window
遵循Angular依赖注入规范,通过DOCUMENT获取window对象,同时配合环境判断:
import { Component, Inject, PLATFORM_ID } from '@angular/core'; import { isPlatformBrowser, DOCUMENT } from '@angular/common'; import { fromEvent, Observable } from 'rxjs'; @Component({ selector: 'app-root', templateUrl: './app.component.html', styleUrls: ['./app.component.css'] }) export class AppComponent { private ScrollWatcher!: Observable<Event>; constructor( @Inject(PLATFORM_ID) private platformId: Object, @Inject(DOCUMENT) private document: Document ) { if (isPlatformBrowser(this.platformId)) { // 通过document.defaultView获取window对象 this.ScrollWatcher = fromEvent(this.document.defaultView!, 'scroll'); } } }
额外注意事项
- 如果
ScrollWatcher在模板中使用async管道,需添加环境判断避免SSR报错,比如用*ngIf="isPlatformBrowser(platformId)"包裹相关模板元素,或者初始化一个空的Observable(new Observable())作为默认值。 - 禁止在类的属性初始化阶段直接访问
window,因为类初始化逻辑会在SSR过程中执行,此时window尚未存在。
内容的提问来源于stack exchange,提问作者Optiq
相关产品推荐
相关产品推荐

