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

Angular Universal中Hammer的使用方法及window未定义错误修复求助

在Angular Universal中使用HammerJS并修复window is not defined错误

先搞清楚错误根源

你碰到的这个报错,本质是HammerJS的核心代码直接依赖了浏览器的window全局对象,但Angular Universal是服务端渲染(SSR),运行在Node.js环境里——这里根本没有浏览器专属的window对象。当服务端打包执行时,HammerJS试图访问不存在的window,自然就抛出了引用错误。

解决方案:分三种场景处理

场景1:组件内按需初始化Hammer(最推荐)

这种方式严格控制Hammer只在浏览器环境下加载和初始化,完全避开服务端的环境问题:

  1. 先安装依赖包:
npm install hammerjs @types/hammerjs --save
  1. 在你的组件中,借助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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.20 10:21:49