Angular结合AGM首次加载地图渲染耗时过长问题咨询
嗨,我之前在项目里用AGM渲染几百个标记点时也踩过这个坑,页面直接卡半分钟才反应过来,太难受了!下面几个优化方案亲测有效,你可以挨个试试:
1. 优先用标记聚类(最省心的方案)
AGM自带了agm-marker-cluster组件,能把近距离的标记自动聚合成一个集群标记,点击集群才会展开显示具体的点。这样原本420个标记可能会变成十几个集群,渲染压力瞬间下降,页面基本不会卡了。
用法很简单,把原来的agm-marker都包裹在agm-marker-cluster里就行:
<agm-map [latitude]="lat" [longitude]="lng"> <agm-marker-cluster> <agm-marker *ngFor="let marker of markers" [latitude]="marker.lat" [longitude]="marker.lng"> </agm-marker> </agm-marker-cluster> </agm-map>
你还可以自定义集群的样式、图标,这个方案见效最快,推荐先试这个。
2. 给标记组件启用OnPush变更检测
每个agm-marker都是一个Angular组件,默认的变更检测策略会频繁检查所有组件状态,420个组件的话会给Angular带来极大压力。把标记组件的变更检测改成OnPush,只有当输入属性变化时才触发检测,能减少很多不必要的计算。
如果是你自己封装的标记组件,直接在@Component里配置:
import { ChangeDetectionStrategy, Component } from '@angular/core'; @Component({ selector: 'app-custom-marker', templateUrl: './custom-marker.component.html', changeDetection: ChangeDetectionStrategy.OnPush // 启用OnPush }) export class CustomMarkerComponent { @Input() markerData: any; }
如果用的是AGM原生的agm-marker,可以考虑自己封装一层,把输入属性传递进去,然后给封装的组件加OnPush。
3. 用Google Maps原生API创建标记
AGM的组件封装虽然方便,但每个组件都有Angular的生命周期和变更检测开销。直接用Google Maps原生API创建标记,绕过Angular的组件树,性能会提升很多。
步骤大概是这样:
- 在
agm-map的mapReady事件里拿到原生地图实例:
<agm-map [latitude]="lat" [longitude]="lng" (mapReady)="onMapReady($event)"></agm-map>
- 在组件里保存地图实例,然后循环创建原生标记:
private map: google.maps.Map; onMapReady(map: google.maps.Map) { this.map = map; this.renderMarkers(); } renderMarkers() { // 先清除旧标记(如果需要) // 然后遍历你的数据源创建标记 this.markers.forEach(markerData => { new google.maps.Marker({ position: { lat: markerData.lat, lng: markerData.lng }, map: this.map, // 其他属性比如标题、图标等 }); }); }
这种方式完全脱离Angular的组件体系,渲染速度会快很多,唯一的缺点是需要自己管理标记的更新、删除等操作,但对于大量标记来说,这点代价很值得。
4. 只渲染当前视野内的标记
如果不想用聚类,还可以监听地图的视野变化,只渲染当前视口范围内的标记点。比如维护一个visibleMarkers数组,当地图视野改变时,计算哪些标记在当前 bounds 内,更新这个数组,然后*ngFor只遍历visibleMarkers。
实现思路:
- 监听地图的
boundsChange事件(AGM里是boundsChange) - 拿到当前地图的 bounds,遍历所有标记,判断是否在 bounds 内
- 更新
visibleMarkers数组,Angular会自动渲染这些标记
这样每次只渲染几十上百个标记,页面就不会卡了。
按照我的经验,先试标记聚类,基本上能解决大部分性能问题;如果聚类不符合你的需求,再试试原生API或者视野过滤的方案。
内容的提问来源于stack exchange,提问作者Moayad Ahmad




