Angular中返回组件后Leaflet地图加载异常问题求助
问题描述
首次加载页面时,Leaflet 可正常加载所有元素;但在 Angular 项目中,进入其他组件后再返回包含 Leaflet 地图的组件时,出现地图加载异常(截图:
)。
项目的 index.html 代码如下:
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no" /> <link rel="icon" type="image/x-icon" href="favicon.ico"> <script src="https://unpkg.com/leaflet@1.6.0/dist/leaflet.js" integrity="sha512-gZwIG9x3wUXg2hdXF6+rVkLF/0Vi9U8D2Ntg4Ga5I5BZpVkVxlJWbSQtXPSiUTtC0TjtGOmxa1AJPuV0CPthew==" crossorigin=""></script> <script src="https://unpkg.com/leaflet-routing-machine@latest/dist/leaflet-routing-machine.js"></script> <!-- <script type="text/javascript" src="node_modules/leaflet.markercluster/dist/leaflet.markercluster-src.js"></script> --> <script src='https://api.mapbox.com/mapbox.js/plugins/leaflet-markercluster/v0.4.0/leaflet.markercluster.js'></script> <link rel="stylesheet" href="https://unpkg.com/leaflet@1.6.0/dist/leaflet.css" integrity="sha512-xwE/Az9zrjBIphAcBb3F6JVqxf46+CDLwfLMHloNu6KEQCAWi6HcDUbeOfBIptF7tcCzusKFjFw2yuvEpDL9wQ==" crossorigin=""/> <link rel="stylesheet" href="https://unpkg.com/leaflet.markercluster@1.4.1/dist/MarkerCluster.css" /> <link rel="stylesheet" href="https://unpkg.com/leaflet.markercluster@1.4.1/dist/MarkerCluster.Default.css"> <!--whitelist https://github.com/apache/cordova-plugin-whitelist#content-security-policy--> <meta http-equiv="Content-Security-Policy" content="script-src 'self' 'unsafe-eval' 'unsafe-inline'; object-src 'self'; style-src 'self' 'unsafe-inline'; media-src *"> </head> <body> <app-root></app-root> </body> </html>
解决方案
这类问题核心是 Angular 组件销毁重建时,Leaflet 地图实例未被正确清理,或地图容器尺寸未重新计算导致的,可通过以下步骤修复:
1. 组件内管理地图实例,销毁时清理
在地图组件中维护地图对象引用,组件销毁时调用 Leaflet 的销毁方法释放资源:
import { Component, OnInit, OnDestroy, ElementRef } from '@angular/core'; declare var L: any; @Component({ selector: 'app-map', templateUrl: './map.component.html', styleUrls: ['./map.component.css'] }) export class MapComponent implements OnInit, OnDestroy { private map: any; constructor(private el: ElementRef) { } ngOnInit(): void { // 初始化地图 this.map = L.map(this.el.nativeElement.querySelector('#map')).setView([51.505, -0.09], 13); L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', { attribution: '© OpenStreetMap contributors' }).addTo(this.map); } ngOnDestroy(): void { // 销毁地图实例 if (this.map) { this.map.remove(); this.map = null; } } }
2. 返回组件时重算地图尺寸
如果返回后地图出现瓦片加载不全、错位的情况,可在组件激活时调用 Leaflet 的 invalidateSize 方法:
import { Component, OnInit, OnDestroy, AfterViewChecked } from '@angular/core'; import { Router, NavigationEnd } from '@angular/router'; import { filter } from 'rxjs/operators'; @Component({ selector: 'app-map', templateUrl: './map.component.html', styleUrls: ['./map.component.css'] }) export class MapComponent implements OnInit, OnDestroy, AfterViewChecked { private map: any; private isMapReady = false; constructor(private router: Router) { } ngOnInit(): void { // 初始化地图 this.map = L.map('map').setView([51.505, -0.09], 13); L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', { attribution: '© OpenStreetMap contributors' }).addTo(this.map); this.isMapReady = true; // 监听路由返回事件,触发尺寸重算 this.router.events.pipe( filter(event => event instanceof NavigationEnd) ).subscribe(() => { if (this.map) { setTimeout(() => { this.map.invalidateSize(); }, 0); } }); } ngAfterViewChecked(): void { if (this.isMapReady) { setTimeout(() => { this.map.invalidateSize(); }, 0); } } ngOnDestroy(): void { if (this.map) { this.map.remove(); this.map = null; } } }
3. 改用 npm 引入 Leaflet(可选优化)
建议通过 npm 安装 Leaflet 及其插件,替代全局引入,更适配 Angular 模块系统:
npm install leaflet leaflet-routing-machine leaflet.markercluster
在组件中引入:
import * as L from 'leaflet'; import 'leaflet-routing-machine'; import 'leaflet.markercluster';
并在 angular.json 中配置样式:
"styles": [ "node_modules/leaflet/dist/leaflet.css", "node_modules/leaflet.markercluster/dist/MarkerCluster.css", "node_modules/leaflet.markercluster/dist/MarkerCluster.Default.css", "src/styles.css" ]
内容的提问来源于stack exchange,提问作者muricoto
相关产品推荐
相关产品推荐

