Angular 15 Google Maps标记位置无法实时更新的解决方案求助
问题:Angular Google Map标记位置无法随数组更新
我用@angular/google-maps结合新南威尔士州交通开放数据搭建了公共交通实时地图,已成功初始化地图并添加渡轮位置标记,但更新标记数组后,地图上的标记位置未同步变化。不过通过组件内的*ngFor循环输出文本时,视图中的数据能正常更新。
核心疑问:标记数组更新时,如何让Angular Google Map中的标记位置同步更新?
当前实现代码
livedata-map-content.component.html
<div class="live-transport-map"> <div *ngIf="apiLoaded" class="google-maps-container"> <google-map width="100%" height="100%" [options]="options"> <map-marker *ngFor="let marker of markers" [position]="marker.position" [label]="marker.label" [title]="marker.title" [options]="marker.options"> </map-marker> <span *ngFor="let marker of markers">NAME: {{marker.title}} LAT: {{marker.position.lat}} LNG: {{marker.position.lng}}!!!! </span> </google-map> </div> </div>
livedata-map-content.component.ts
import { ChangeDetectorRef, Component, AfterViewInit, OnDestroy } from '@angular/core'; import { MapService} from '../../../services/map.service'; import { interval, Subject } from 'rxjs'; import { takeUntil } from 'rxjs/operators'; @Component({ selector: 'app-livedata-map-content', templateUrl: './livedata-map-content.component.html', styleUrls: ['./livedata-map-content.component.scss'] }) export class LivedataMapContentComponent implements AfterViewInit, OnDestroy { public apiLoaded: any = false; public markers: Array<any> = []; public period = 10000; public iconStr = "http://maps.google.com/mapfiles/ms/icons/green-dot.png"; private destroy$ = new Subject<void>(); public options: google.maps.MapOptions = { center: {lat: -33.853759, lng: 151.212803}, // 悉尼港中心 zoom: 14, }; constructor( private mapService: MapService, private cd: ChangeDetectorRef ) { } ngAfterViewInit(): void { // 视图初始化后加载地图API this.mapService.loadGoogleMapsAPI().subscribe(data => { this.apiLoaded = data; if(this.apiLoaded === true) { // API加载完成后启动实时数据更新 interval(this.period) .pipe(takeUntil(this.destroy$)) .subscribe(() => this.updateMarkers()); } }); // 初始化地图标记 this.mapService.getLivePositionData('ferry').subscribe(positionData => { let transportEntitiesArray = positionData.data.entity; transportEntitiesArray.forEach((transportEntity: any) => { this.markers.push({ tripId: transportEntity.vehicle.trip.tripId, position: { lat: transportEntity.vehicle.position.latitude, lng: transportEntity.vehicle.position.longitude, }, title: transportEntity.vehicle.vehicle.id + '\n' + transportEntity.vehicle.vehicle.label, options: { icon: this.iconStr, } }); }); this.cd.detectChanges(); }); } updateMarkers = () => { this.mapService.getLivePositionData('ferry').subscribe(positionData => { positionData.data.entity.forEach(positionDataItem => { this.markers.forEach(marker => { // 仅更新有位置变化的标记 if(marker.tripId === positionDataItem.vehicle.trip.tripId && (marker.position.lat !== positionDataItem.vehicle.position.latitude || marker.position.lng !== positionDataItem.vehicle.position.longitude)){ // 创建新的position对象替换旧引用,触发变更检测 marker.position = { lat: positionDataItem.vehicle.position.latitude, lng: positionDataItem.vehicle.position.longitude }; } }); }); this.cd.detectChanges(); }); } ngOnDestroy(): void { this.destroy$.next(); this.destroy$.complete(); } }
map.service.ts
... public loadGoogleMapsAPI = () => { const mapsAPIURL = `https://maps.googleapis.com/maps/api/js?key=${environment.tempGoogleMapsID}` console.log('mapsAPIURL ',mapsAPIURL); return this.http.jsonp<any>(mapsAPIURL, 'callback').pipe( map((data) => { console.log('DATA ',data); return true}), catchError((error) => { console.log('error ',error); return of(false)}), ); } ... getLivePositionData = (transportMode: any) => { const getLivePositionDataObject = { transportMode: transportMode } const getLivePositionDataDataURL = this.openDataAPI + 'positiondata'; return this.http.post<any>(getLivePositionDataDataURL, getLivePositionDataObject); } ...
当前地图可正常绘制并填充标记数组,但标记位置无法在地图上更新:

问题原因及解决方案
问题根源
Angular的变更检测默认通过引用比较判断值是否变化,而你直接修改了marker.position对象内部的lat和lng属性,没有改变position对象的引用。@angular/google-maps的map-marker组件依赖输入属性的引用变化来触发更新,因此不会同步位置变更。
修复步骤
修改updateMarkers方法中更新位置的逻辑,创建新的position对象替换旧引用:
marker.position = { lat: positionDataItem.vehicle.position.latitude, lng: positionDataItem.vehicle.position.longitude };
额外优化
- 替换setInterval为RxJS interval:避免内存泄漏,方便组件销毁时清理定时任务(已在代码示例中实现)。
- 补全ChangeDetectorRef注入:原代码构造函数中缺失该依赖注入,需添加(已修正)。
内容的提问来源于stack exchange,提问作者CVL
相关产品推荐
相关产品推荐

