Vue中加载Google Map API报错:google未定义 求助
Got it, let's break down why you're hitting this error and walk through solid fixes.
The Root Cause
Your current setup has two critical timing issues:
- Vue Lifecycle Order: Parent components run their
mountedhook after all child components have already executed theircreatedandmountedhooks. By the time you inject the Google Maps script in the parent'smounted, your child component has already tried (and failed) to access thegoogleobject. - Asynchronous Script Loading: Adding a script tag dynamically is an async operation—you can't immediately use
googleright after appending the script, since it needs time to download and execute.
Solution 1: Load Script Early & Control Child Rendering
The most reliable approach is to load the Google Maps script in the parent's created hook, wrap the script load in a promise, and only render the child component once the script is fully loaded.
Parent Component Code
<template> <div class="map-container"> <!-- Only render child when script is loaded --> <MapChild v-if="isMapScriptLoaded" /> </div> </template> <script> import MapChild from './MapChild.vue'; export default { components: { MapChild }, data() { return { isMapScriptLoaded: false }; }, created() { this.loadGoogleMaps(); }, methods: { loadGoogleMaps() { // Avoid reloading if script is already loaded if (window.google) { this.isMapScriptLoaded = true; return; } const script = document.createElement('script'); script.src = 'https://maps.googleapis.com/maps/api/js?key=YourActualAPIKey'; script.async = true; script.defer = true; // Handle successful script load script.onload = () => { this.isMapScriptLoaded = true; console.log('Google Maps script loaded successfully'); }; // Handle load errors script.onerror = () => { console.error('Failed to load Google Maps script'); }; document.head.appendChild(script); } } }; </script>
Child Component Code
Now your child can safely access google in its mounted hook:
<template> <div id="map" style="width: 100%; height: 400px;"></div> </template> <script> export default { mounted() { // Initialize map - google is guaranteed to exist here const map = new window.google.maps.Map(document.getElementById('map'), { center: { lat: -34.397, lng: 150.644 }, zoom: 8 }); } }; </script>
Solution 2: Use Event Communication (Alternative)
If you prefer not to use v-if to control rendering, you can emit an event from the parent once the script loads, then have the child listen for that event to initialize the map.
Parent Component Adjustment
Update the onload handler to emit an event:
script.onload = () => { this.$emit('maps-loaded'); console.log('Google Maps script loaded successfully'); };
Child Component Adjustment
Listen for the event and initialize the map when it fires:
<script> export default { mounted() { // Listen for the parent's loaded event this.$parent.$on('maps-loaded', this.initMap); }, beforeUnmount() { // Clean up the event listener to avoid memory leaks this.$parent.$off('maps-loaded', this.initMap); }, methods: { initMap() { const map = new window.google.maps.Map(document.getElementById('map'), { center: { lat: -34.397, lng: 150.644 }, zoom: 8 }); } } }; </script>
Quick Fix (For Small Apps)
If you don't mind a slight hit to initial page load performance, you can load the script directly in your index.html file. This ensures the script starts loading before Vue even initializes:
<!-- Add this to your public/index.html <head> --> <script src="https://maps.googleapis.com/maps/api/js?key=YourActualAPIKey" async defer></script>
Then in your child component, you can still add a quick check to make sure google is available before initializing:
mounted() { // Wait for the script to load if it's still pending const checkGoogle = setInterval(() => { if (window.google) { clearInterval(checkGoogle); this.initMap(); } }, 100); }
Key Notes
- Always verify your API key is valid and that the Maps JavaScript API is enabled in your Google Cloud Console.
- Avoid loading the script multiple times—check
window.googlefirst before injecting a new script tag.
内容的提问来源于stack exchange,提问作者Justin

