Angular加载Google Maps GeoJSONP报eqfeed_callback未定义
问题描述
Angular项目复现Google Maps导入数据示例时控制台抛出错误:
earthquake_GeoJSONP.js:1 Uncaught ReferenceError: eqfeed_callback is not defined at earthquake_GeoJSONP.js:1:1
页面仅能正常加载基础地形地图,无法渲染地震点位标记。
- 项目环境:Angular CLI 13.3.7、Node 16.14.2、npm 8.5.0(Windows 64位)
- 已安装依赖:
@googlemaps/js-api-loader、@types/google.maps
原始问题代码如下:
app.component.ts
import { Component, OnInit } from '@angular/core'; import { Loader } from "@googlemaps/js-api-loader" @Component({ selector: 'app-root', templateUrl: './app.component.html', styleUrls: ['./app.component.css'] }) export class AppComponent implements OnInit{ title = 'map'; ngOnInit() { let map: google.maps.Map; const loader = new Loader({ apiKey: "YOUR_API_KEY" }); loader.load().then(() => { const map = new google.maps.Map(document.getElementById("map") as HTMLElement, { zoom: 2, center: new google.maps.LatLng(2.8, -187.3), mapTypeId: "terrain", }); // map.data.loadGeoJson('data.json'); // Create a <script> tag and set the USGS URL as the source. const script = document.createElement("script"); // This example uses a local copy of the GeoJSON stored at // http://earthquake.usgs.gov/earthquakes/feed/v1.0/summary/2.5_week.geojsonp script.src = "https://developers.google.com/maps/documentation/javascript/examples/json/earthquake_GeoJSONP.js"; document.getElementsByTagName("head")[0].appendChild(script); const eqfeed_callback = function (results: any) { for (let i = 0; i < results.features.length; i++) { const coords = results.features[i].geometry.coordinates; const latLng = new google.maps.LatLng(coords[1], coords[0]); let marker = new google.maps.Marker({ position: latLng, map: map, }); // place marker in map marker.setMap(map) } }; }); } }
app.component.html
<div id="map"></div>
app.component.css
#map { height: 500px; width: 100%; }
预期效果:在地图上加载展示所有地震点位标记。
错误原因
- 作用域问题:
eqfeed_callback定义在loader.load()的then回调块级作用域内,没有挂载到全局window对象上。而GeoJSONP脚本加载完成后会直接调用全局作用域下的eqfeed_callback函数,因此触发未定义错误。 - 执行顺序问题:代码先插入script标签加载GeoJSONP资源,后定义回调函数,极端场景下即使回调挂到全局也可能出现脚本加载完成时回调还未定义的问题。
- 冗余代码问题:代码中重复声明
map变量,且创建Marker时已经传入map: map参数,后续重复调用marker.setMap(map)属于多余逻辑。
修复方案
- 调整执行顺序:在插入script标签加载GeoJSONP资源前,就把
eqfeed_callback挂载到全局window对象上,确保脚本执行时回调已经存在。 - 移除重复的
map变量声明,删除冗余的setMap调用。 - 处理TypeScript类型校验问题,可通过全局类型声明避免挂载window属性时的类型报错。
修正后的app.component.ts核心代码如下:
import { Component, NgZone, OnInit } from '@angular/core'; import { Loader } from "@googlemaps/js-api-loader" // 声明全局window上的回调类型,避免TS校验报错 declare global { interface Window { eqfeed_callback: (results: any) => void; } } @Component({ selector: 'app-root', templateUrl: './app.component.html', styleUrls: ['./app.component.css'] }) export class AppComponent implements OnInit{ title = 'map'; map?: google.maps.Map; constructor(private ngZone: NgZone) {} ngOnInit() { const loader = new Loader({ apiKey: "YOUR_API_KEY" }); loader.load().then(() => { this.map = new google.maps.Map(document.getElementById("map") as HTMLElement, { zoom: 2, center: new google.maps.LatLng(2.8, -187.3), mapTypeId: "terrain", }); // 必须在插入script标签前定义全局回调 window.eqfeed_callback = (results: any) => { // 用ngZone保证回调执行时触发Angular变更检测 this.ngZone.run(() => { if (!this.map) return; for (let i = 0; i < results.features.length; i++) { const coords = results.features[i].geometry.coordinates; const latLng = new google.maps.LatLng(coords[1], coords[0]); new google.maps.Marker({ position: latLng, map: this.map, }); } }) }; // 回调定义完成后再加载GeoJSONP脚本 const script = document.createElement("script"); script.src = "https://developers.google.com/maps/documentation/javascript/examples/json/earthquake_GeoJSONP.js"; document.getElementsByTagName("head")[0].appendChild(script); }); } }
提示:组件销毁时记得移除动态插入的script标签、销毁地图实例避免内存泄漏。
内容的提问来源于stack exchange,提问作者NEGG
相关产品推荐
相关产品推荐

