Angular Universal中Hammer的使用方法及window未定义错误修复求助
在Angular Universal中使用HammerJS并修复
window is not defined错误 先搞清楚错误根源
你碰到的这个报错,本质是HammerJS的核心代码直接依赖了浏览器的window全局对象,但Angular Universal是服务端渲染(SSR),运行在Node.js环境里——这里根本没有浏览器专属的window对象。当服务端打包执行时,HammerJS试图访问不存在的window,自然就抛出了引用错误。
解决方案:分三种场景处理
场景1:组件内按需初始化Hammer(最推荐)
这种方式严格控制Hammer只在浏览器环境下加载和初始化,完全避开服务端的环境问题:
- 先安装依赖包:
npm install hammerjs @types/hammerjs --save
- 在你的组件中,借助Angular的平台判断工具区分环境:
import { Component, OnInit, Inject, PLATFORM_ID } from '@angular/core'; import { isPlatformBrowser } from '@angular/common'; import * as Hammer from 'hammerjs'; @Component({ selector: 'app-your-component', templateUrl: './your-component.component.html' }) export class YourComponent implements OnInit { constructor(@Inject(PLATFORM_ID) private platformId: Object) {} ngOnInit(): void { // 仅在浏览器环境下执行Hammer相关逻辑 if (isPlatformBrowser(this.platformId)) { const targetElement = document.getElementById('gesture-target'); if (targetElement) { const hammerInstance = new Hammer(targetElement); // 绑定你需要的手势事件,比如pan、swipe hammerInstance.on('pan', (event) => { console.log('Pan gesture detected:', event); // 这里写你的业务逻辑 }); } } } }
场景2:全局引入Hammer时的兼容处理(不推荐,仅应急用)
如果你之前在polyfills.ts里全局引入了import 'hammerjs';,服务端打包肯定会报错。这时候可以在server.ts里给Node.js环境模拟一个基础的window对象:
// 在server.ts的最顶部添加这段代码 (global as any).window = {}; (global as any).document = { createElement: () => ({}) };
⚠️ 注意:这种模拟只是临时救急,Hammer可能还依赖其他浏览器API,后续可能出现其他奇怪问题,优先用场景1的方案。
场景3:动态导入Hammer(适合懒加载场景)
如果你的组件是懒加载的,或者希望Hammer只在需要的时候才加载,可以用动态导入的方式:
import { Component, OnInit, Inject, PLATFORM_ID } from '@angular/core'; import { isPlatformBrowser } from '@angular/common'; @Component({ selector: 'app-lazy-component', templateUrl: './lazy-component.component.html' }) export class LazyComponent implements OnInit { constructor(@Inject(PLATFORM_ID) private platformId: Object) {} async ngOnInit(): Promise<void> { if (isPlatformBrowser(this.platformId)) { // 动态导入HammerJS,仅在浏览器环境下加载 const HammerModule = await import('hammerjs'); const Hammer = HammerModule.default; const targetElement = document.getElementById('lazy-gesture-target'); if (targetElement) { const hammerInstance = new Hammer(targetElement); hammerInstance.on('swipe', (event) => { console.log('Swipe gesture detected:', event); }); } } } }
最后再划个重点
不管用哪种方案,核心思路都是让HammerJS的代码只在浏览器环境下运行,彻底避开服务端的Node.js环境。这样就能从根源上解决那个window is not defined的错误了。
内容的提问来源于stack exchange,提问作者kamalav
相关产品推荐
相关产品推荐

