Google Maps API 有一个非常严重的错误,它会一直持续到页面重新加载:https ://issuetracker.google.com/issues/35821412
这会在 SPA 和 Lit 等 Web 组件框架中产生问题,因为地图不包含在组件中,它由事件侦听器附加到窗口。
创建它很容易,但我要补充一点,您要确保 API 每页只加载一次,因此您需要某种已经加载的全局日志。
像这样的东西:
/** URI of the Maps JS library */
const googleMapsApi = `https://maps.googleapis.com/maps/api/js?key=API_KEY&libraries=places&callback=initMapApi`;
/** Flag indicating that mapping library is currently being loaded, wait for it to . */
let mapLoading = false;
/** Flag indicating that mapping library has been downloaded. */
let mapReady = false;
// Set window level function for maps API to call back to
(window as any).initMapApi = function () {
mapReady = true;
delete (window as any).initMapApi;
}
/** Call this before calling maps API methods to make sure that it's loaded.
* @returns {Promise<boolean>} True once loaded. */
export async function mapApiLoaded() {
if (mapReady)
return true;
while (mapLoading)
await new Promise(requestAnimationFrame);
if (mapReady)
return true;
try {
mapLoading = true;
// Get the API key for the current user
const google = // your key;
if (!google)
return;
const mapApiUri = googleMapsApi.replace('API_KEY', google);
// Add a <script> tag pointing to the API with the key
await new Promise((resolve, reject) => {
const script = document.createElement('script') as HTMLScriptElement;
script.type = 'text/javascript';
script.onload = resolve;
script.onerror = reject;
document.getElementsByTagName('head')[0].appendChild(script);
script.src = mapApiUri;
});
// Wait for the script to fire the callback method
while (!mapReady)
await new Promise(requestAnimationFrame);
console.log('️ API loaded.');
}
finally { mapLoading = false; }
return mapReady;
}
一旦你有了它,你就可以在每个地图组件的firstUpdated
或中调用它connectedCallback
。
但是,由于内存泄漏,如果您创建大量此类映射并拥有一个单页应用程序,您将很快遇到问题 - 您传递给的每个元素new google.maps.Map
都会附加到窗口,直到用户刷新,并且没有办法断开它。
您仍然可以将 Google Maps API 与 SPA 一起使用,但您必须重复使用地图实例......
connectedCallback
检查现有地图元素并在未连接时重新使用。
- 在
disconnectedCallback
明确的路线/标记/等上并缓存地图以供重用。
所以你的代码最终是这样的:
@customElement('map-element')
class MapElement
extends LitElement {
render() {
return html `<div id="map"></div>`;
}
@query('#map')
private mapWrapper: HTMLDivElement;
private map: google.maps.Map;
async connectedCallback() {
await mapApiLoaded();
const oldMap = window.oldMaps.pop() // Or however you get your previously used maps
if (!oldMap)
// Create new map in your wrapper
this.map = new google.maps.Map(this.mapWrapper, ...your options);
else {
// Reconfig old map and add it to your wrapper
oldMap.setOptions(...your options);
this.map = oldMap;
this.mapWrapper.appendChild(oldMap);
}
}
disconnectedCallback() {
if(!this.map) return;
// Remove from shadow DOM
this.map.remove();
// Clear markers/routes from this.map
// Add to register of unused maps, say...
window.oldMaps.push(this.map);
}
}