Google Maps JavaScript API with lit-element



我正在尝试使用lit-html创建一个自定义元素,该元素使用Google Maps API。如何使其协同工作?以下是我目前所拥有的:

地图元素.css:

#map {
height: 400px;  /* The height is 400 pixels */
width: 100%;  /* The width is the width of the web page */
background-color: grey;
}

map element.js:

import {
LitElement,
html
} from '@polymer/lit-element';
class MapElement extends LitElement {
render() {
return html `
<link rel="stylesheet" href="map-element.css">
<div id="map"></div>
<script>
function initMap() {
// The location of Uluru
var uluru = {lat: -25.344, lng: 131.036};
// The map, centered at Uluru
var map = new google.maps.Map(
this.shadowRoot.querySelector('#map'), {zoom: 14, center: uluru});
// The marker, positioned at Uluru
var marker = new google.maps.Marker({position: uluru, map: map});
}
</script>
<script async defer
src="https://maps.googleapis.com/maps/api/js?key=MYAPIKEY&callback=initmap">
</script>
`;
}

}
customElements.define('map-element', MapElement);

输出只是带有map ID的div的占位符,我没有得到任何错误。

以下是我试图在元素中使用的代码的参考:https://developers.google.com/maps/documentation/javascript/adding-a-google-map

您可以在connectedCallback方法中添加Script,以确保在组件包含在DOM 中时包含它

constructor() {
this.callbackName = 'initMap';
this.mapsUrl = https://maps.googleapis.com/maps/api/js?key=MYAPIKEY
}
connectedCallback() {
window[this.callbackName] = this._initMap.bind(this)
this._addMapScript() // This
}
addScript: function() {
var script = document.createElement('script');
script.src = `${this.mapsUrl}&callback=${this.callbackName}`;
var s = document.querySelector('script') || document.body;
s.parentNode.insertBefore(script, s);
}
_initMap() {
// To be we have shadow DOM ready.
this.updateCompleted.then(this.initMap);
}
initMap() {
// Your code here
}

像这样的东西应该可以

Google Maps API有一个非常严重的bug,它会一直持续到页面重新加载:https://issuetracker.google.com/issues/35821412

这在SPAs和像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;
}

一旦有了它,就可以在每个映射组件的firstUpdatedconnectedCallback中调用它。

然而,由于内存泄漏,如果你创建了很多这样的映射,并且只有一个页面应用程序,你会很快遇到问题——你传递给new google.maps.Map的每个元素都会连接到窗口,直到用户刷新,并且没有办法断开它

你仍然可以使用谷歌地图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);
}
}

最新更新