簡體   English   中英

帶有 lit-element 的 Google Maps JavaScript API

[英]Google Maps JavaScript API with lit-element

我正在嘗試使用使用 Google Maps API 的 lit-html 創建自定義元素。 如何讓它協同工作? 這是我到目前為止所擁有的:

地圖元素.css:

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

地圖-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);

輸出只是帶有地圖 ID 的 div 的占位符,我沒有收到任何錯誤。

這是我嘗試在我的元素中使用的代碼的參考: https ://developers.google.com/maps/documentation/javascript/adding-a-google-map

您可以在connectedCallback方法中添加腳本,以確保在組件包含在 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 有一個非常嚴重的錯誤,它一直存在到頁面重新加載: https ://issuetracker.google.com/issues/35821412

這會在 SPA 和網絡組件框架(如 Lit)中產生問題,因為地圖不包含在組件中,它是由事件偵聽器附加到窗口的。

創建它很容易,但我要補充一點,您希望確保每頁僅加載一次 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的每個元素都會附加到窗口,直到用戶刷新,並且沒有辦法斷開它。

您仍然可以將 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);
    }
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM