Angular中Google Maps API偶现Uncaught ReferenceError: google未定义问题
解决Angular中继承
google.maps.OverlayView时出现的"google is not defined"错误 这个问题的核心原因很明确:你用async defer加载Google Maps API的方式,和Angular组件类的解析执行时机冲突了。
async defer会让API脚本在页面DOM加载完成后才开始加载并执行,但Angular组件(包括你在组件内部定义的Popup类)是在模块编译、组件初始化阶段就被TypeScript解析的——这时候如果API还没加载完成,google命名空间自然不存在,就会抛出ReferenceError;偶尔能正常加载只是运气好,API刚好在类解析前加载完了而已。
下面给你两种靠谱的解决方案,适配Angular的开发场景:
方案一:用Promise封装API加载,在组件运行时动态定义Popup类
这种方式不需要修改太多现有代码,核心是把Popup类的定义延迟到API加载完成后执行:
- 修改index.html的API加载脚本,添加回调函数:
<script async defer src="https://maps.googleapis.com/maps/api/js?key=myKey&libraries=places&callback=googleMapsLoaded"></script>
- 创建一个全局的加载Promise(可以放在单独的文件比如
google-maps-loader.ts里):
// 声明google全局变量,避免TypeScript报错 declare const google: any; export const googleMapsLoaded$ = new Promise<void>((resolve) => { // 把回调挂到window上,让API加载完成后触发 (window as any).googleMapsLoaded = () => { resolve(); }; });
- 修改你的MapComponent,在
ngAfterViewInit里等待API加载完成后再定义Popup类:
import { Component, AfterViewInit, OnDestroy } from '@angular/core'; import { googleMapsLoaded$ } from './google-maps-loader'; @Component({ selector: 'app-map', templateUrl: './map.component.html', styleUrls: ['./map.component.scss'], }) export class MapComponent implements AfterViewInit, OnDestroy { map: google.maps.Map; // 先声明Popup类型,后续动态赋值 Popup: typeof google.maps.OverlayView; async ngAfterViewInit() { // 等待Google Maps API加载完成 await googleMapsLoaded$; // 现在可以安全地定义Popup类了 this.Popup = class Popup extends google.maps.OverlayView { // 你的类实现代码 constructor(position: google.maps.LatLng, content: HTMLElement) { super(); this.position = position; this.content = content; // ...其他初始化逻辑 } // 实现OverlayView要求的方法:onAdd, draw, onRemove onAdd() { /* ... */ } draw() { /* ... */ } onRemove() { /* ... */ } }; // 后续创建Popup实例时,用this.Popup // const popup = new this.Popup(myPosition, myContentElement); } // 其他地图相关代码... }
方案二:用APP_INITIALIZER确保API在应用初始化前加载完成
如果希望整个应用启动前就确保Google Maps API加载完成,可以用Angular的APP_INITIALIZER钩子:
- 在app.module.ts中配置初始化器:
import { NgModule, APP_INITIALIZER } from '@angular/core'; import { BrowserModule } from '@angular/platform-browser'; import { AppComponent } from './app.component'; import { MapComponent } from './map/map.component'; declare const google: any; // 定义加载Google Maps的工厂函数 function loadGoogleMaps() { return new Promise<void>((resolve, reject) => { const script = document.createElement('script'); script.src = 'https://maps.googleapis.com/maps/api/js?key=myKey&libraries=places'; script.onload = () => resolve(); script.onerror = () => reject(new Error('加载Google Maps API失败')); document.body.appendChild(script); }); } @NgModule({ declarations: [AppComponent, MapComponent], imports: [BrowserModule], providers: [ { provide: APP_INITIALIZER, useFactory: loadGoogleMaps, multi: true } ], bootstrap: [AppComponent] }) export class AppModule { }
这样Angular会在启动应用前先执行loadGoogleMaps函数,等API加载完成后才会初始化组件——这时候你在组件内部直接定义Popup类就不会再出现google is not defined的错误了。
额外注意事项
- 确保你已经安装了Google Maps的TypeScript类型定义:
npm install @types/googlemaps --save-dev,这样TypeScript不会报类型错误。 - 避免在组件类的顶层直接引用
google命名空间的类型(除非用方案二确保API提前加载),尽量把依赖google的代码放到运行时的生命周期钩子中。
内容的提问来源于stack exchange,提问作者Jus10
相关产品推荐
相关产品推荐

