简体   繁体   中英

can't use imported var from js file in code

I try to use imported vars from a js file into my code but I can't get it to work the excepted way.

location_var.js

var location = {

    place: "Bogotá",
    lat: "4.710988599999999",
    lng: "-74.072092"

};
export { location };

index.html

<script type="module">
    import { location } from './location_var.js'
    console.log(location.lat) // this will be displayed
</script>

but if I put a <script> tag below, I can't use my variables back.

<body>
    <!--The div element for the map -->
    <div id="map"></div>
    <script>
        function initMap() {
            var place = { lat: location.lat, lng: location.lng }; // this doesn't work - console says the vars are undefined for some reasons
            var map = new google.maps.Map(
                document.getElementById('map'), { zoom: 4, center: place });
            var marker = new google.maps.Marker({ position: place, map: map });
        }
    </script>
    <script async defer
        src="https://maps.googleapis.com/maps/api/js?key=API_KEY&callback=initMap">
        </script>
</body>

Any ideas why I can't call it back there?

Variables defined (or imported) in modules have scope only in that module. If a <script type="module"> defines or imports something, it won't be visible in any other <script> tag.

Unlike normal scripts, variable names defined with const / let / var and function declarations do not get put into the global environment, so even if you were to put the imported location into a standalone variable, it wouldn't help.

Another issue is that you have two asynchronous actions going on here: you have to get location_var.js to get the location object, and you also have to wait for the googleapis script to be downloaded. Neither script depends on the other, but you want to run something (initialize the map) after both have completed. To wait for multiple asynchronous things to finish and then run something else, you should use Promise.all , and to use Promise.all , you need to make sure each asynchronous action resolves a Promise once it's done. So, here's one possible approach:

<script>
window.googleScriptPromise = new Promise((resolve) => {
  window.googleScriptCallback = resolve;
});
window.locationPromise = new Promise((resolve) => {
  window.locationResolve = resolve;
});

Promise.all([
  locationPromise
  googleScriptPromise,
])
  .then(([location]) => {
    // now, location will refer to the imported location, and google maps will have been loaded
  });
</script>

<script async defer
    src="https://maps.googleapis.com/maps/api/js?key=API_KEY&callback=googleScriptCallback">
    </script>
<script type="module">
  import { location } from './location_var.js'
  window.locationPromise(location);
</script>

That preserves your current <script> structure, but it relies on a bunch of global variables. It would probably be a lot better if you didn't have a separate <script> tag for the bulk of the code, and instead put most of it in the module, that way you only have to call .then on the Google promise:

<script>
// must use a normal script tag to assign the Promise to window synchronously
window.googleScriptPromise = new Promise((resolve) => {
  window.googleScriptCallback = resolve;
});
</script>
<script async defer
    src="https://maps.googleapis.com/maps/api/js?key=API_KEY&callback=googleScriptCallback">
    </script>
<script type="module">
import { location } from './location_var.js'
window.googleScriptPromise.then(() => {
  // now, location will refer to the imported location, and google maps will have been loaded
});
</script>

If you're able to change where the bulk of your <script> is, the above approach is cleaner and definitely preferable.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM