简体   繁体   English

VueJS:谷歌地图在数据准备好之前加载 - 如何让它等待? (Nuxt)

[英]VueJS: Google Maps loads before data is ready - how to make it wait? (Nuxt)

This is my first VueJS project and I've got vue2-google-maps up and running but I've come across an issue when I attempt to connect the map markers to my site's JSON feed (using the Wordpress REST API), the Lat and Lng values are returning undefined or NaN . 这是我的第一个VueJS项目,我已经启动并运行了vue2-google-maps但是当我尝试将地图标记连接到我的网站的JSON提要(使用Wordpress REST API)时,我遇到了一个问题, LatLng值返回undefinedNaN

On further investigation (thanks to @QuỳnhNguyễn below) it seems like the Google Maps instance is being run before the data is ready. 在进一步调查时(感谢下面的@QuỳnhNguyễn),似乎在数据准备好之前正在运行Google Maps实例。 I have tried watching for the feed to be loaded before initialising the map, but it doesn't seem to work. 在初始化地图之前,我已经尝试过观看要加载的Feed,但它似乎不起作用。

The marker locations are pulled in from the WordPress REST API using JSON and exist in an array (locations). 标记位置使用JSON从WordPress REST API中提取并存在于数组(位置)中。 The array is present and populated in Vue Dev Tools (51 records), but when checking on mounted , the array is empty. 该数组存在并填充在Vue Dev Tools(51条记录)中,但在检查已安装时 ,该数组为空。 The data is pulled in at the created stage, so I don't know why it wouldn't be ready by the mounted stage. 数据在创建阶段被拉入,所以我不知道为什么安装阶段不会准备好。

The code in question is as below... 有问题的代码如下......

Template: 模板:

<template>
    <gmap-map v-if="feedLoaded" ref="map" :center="center" :zoom="zoom" :map-type-id="mapTypeId" :options="options">
        <gmap-marker 
            :key="index" v-for="(m, index) in locations" 
            :position="{ lat: parseFloat(m.place_latitude), lng: parseFloat(m.place_longitude) }" 
            @click="toggleInfoWindow(m,index)" 
            :icon="mapIconDestination">
        </gmap-marker>
        <gmap-info-window></gmap-info-window>
    </gmap-map>
</template>

Script 脚本

<script>
    const axios = require('axios');
    const feedURL = "API_REF";

    export default {
        props: {
            centerRef: {
                type: Object,
                default: function() {
                    return { lat: -20.646378400026226, lng: 116.80669825605469 }
                }
            },
            zoomVal: {
               type: Number,
               default: function() {
                   return 11
               }
            }
        },
        data: function() {
            return {
                feedLoaded: false,
                zoom: this.zoomVal,
                center: this.centerRef,
                options: {
                    mapTypeControl: false,
                    streetViewControl: false,
                },
                mapTypeId: 'styledMapType',
                mapIconDestination: '/images/map-pin_destination.png',
                mapIconActivity: '/images/map-pin_activity.png',
                mapIconAccommodation: '/images/map-pin_accommodation.png',
                mapIconEvent: '/images/map-pin_event.png',
                mapIconBusiness: '/images/map-pin_business.png',
                locations: [],
                markers: []
            }
        },
        created: function() {
            this.getData();
        },
        mounted: function() {
            this.$nextTick(() => {
                this.$refs.karrathaMap.$mapPromise.then((map) => {
                    var styledMapType = new google.maps.StyledMapType(
                        [...MAP_STYLE SETTINGS...]
                    )
                    map.mapTypes.set('styled_map', styledMapType);
                    map.setMapTypeId('styled_map');

                })

            });
        },
        watch: {
            feedLoaded: function() {
                if (this.feedLoaded == true) {
                    console.log(JSON.stringify(this.locations))
                }
            }
        },
        methods: {
            getData() {
                const url = feedURL;
                axios
                    .get(url)
                    .then((response) => {this.locations = response.data;})
                    .then(this.feedLoaded = true)
                    .catch( error => { console.log(error); }
                );
            }
        }
    }
</script>

It turns out the issue was dirty data. 事实证明问题是脏数据。

The JSON response was including locations that were not supposed to be included on the map, so it failed every time it came across an entry that didn't include the ACF fields, despite me setting the feed to only return data where include on map was true. JSON响应包括不应该包含在地图上的位置,因此每次遇到不包含ACF字段的条目时都会失败,尽管我将Feed设置为仅返回包含在地图上的数据真正。

I have solved the issue by handling the data once the feed is loaded and creating a new array (markers) from it using the valid data, then using this, rather than the original (locations) array to place the markers on the map. 我已经通过在加载Feed后处理数据并使用有效数据从中创建新数组(标记)来解决问题,然后使用此数据而不是原始(位置)数组将标记放置在地图上。

Cleaning the data: 清理数据:

watch: {
    feedLoaded: function() {
        if (this.feedLoaded == true) {

            var LocationList = this.locations;

            for (var i = 0; i < LocationList.length; i++) {
                var includeOnMap = LocationList[i].acf['place_include-on-map'];

                if (includeOnMap === true) {
                    var placeName = LocationList[i].title.rendered;
                    var placeDescription = LocationList[i].acf['place_short-description'];
                    var placeLatitude = LocationList[i].acf['place_latitude'];
                    var placeLongitude = LocationList[i].acf['place_longitude'];
                    var placeIcon = this.mapIconDestination;

                    this.markers.push({ name: placeName, lat: placeLatitude, lng: placeLongitude, icon: placeIcon });
                }

            }
        }
    }
}

Then, the gmap component : 然后, gmap组件

<gmap-map ref="karrathaMap" :center="center" :zoom="zoom" :map-type-id="mapTypeId" :options="options">
    <gmap-marker v-if="feedLoaded == true" :key="index" v-for="(m, index) in markers" :position="{ lat: parseFloat(m.lat), lng: parseFloat(m.lng) }" @click="toggleInfoWindow(m,index)" :icon="m.icon"></gmap-marker>
    <gmap-info-window></gmap-info-window>
</gmap-map>

Thank you everybody who contributed to helping me get to the bottom of the issue. 谢谢所有帮助我解决问题的人。 I will now spend some time rethinking how the data is structured. 我现在将花一些时间重新思考数据的结构。

It appears to be related with data format. 它似乎与数据格式有关。 According to vue-devtools from provided screenshot your data is returned from WordPress REST API in the following format: 根据提供的屏幕截图中的 vue-devtools ,您可以使用以下格式从WordPress REST API返回数据:

[
  {
    "acf": {
      "place_latitude": "-22.695754",
      "place_longitude": "118.269081",
      "place_short-description": "Karijini National Park"
    },
    "id": 12,
    "parent": 10,
    "title": {
      "rendered": "Karijini National Park"
    }
  },
  ... 
]

Having how locations array is getting initialized ( getData method), position property could be passed like this: 有了如何初始化locations数组( getData方法),可以像这样传递position属性:

<gmap-marker
    :key="index"
    v-for="(m, index) in locations"
    :position="{ lat: parseFloat(m.acf.place_latitude), lng: parseFloat(m.acf.place_longitude) }"
></gmap-marker>

Here is a demo 这是一个演示

vuejs supports v-if directive on elements. vuejs支持元素的v-if指令。 I recommend you try as following code snippet. 我建议您尝试以下代码段。

<template>
  <div id="map" v-if="loaded">
    <gmap-map ref="map" :center="center" :zoom="zoom" :map-type-id="mapTypeId" :options="options">
      <gmap-marker
        :key="index" v-for="(m, index) in locations"
        :position="{ lat: parseFloat(m.place_latitude), lng: parseFloat(m.place_longitude) }"
        @click="toggleInfoWindow(m,index)"
        :icon="mapIconDestination">
      </gmap-marker>
      <gmap-info-window></gmap-info-window>
    </gmap-map>
  </div>
</template>


<script>
  export default {
    data() {
      return {
        loaded: false
      }
    },
    beforeMount: function () {
      const url = feedURL;
      axios
        .get(url)
        .then((response) => {
          this.locations = response.data;
          //activate element after api call response recieved
          this.loaded = true
        })
        .catch(error => {
            console.log(error);
          }
        );
    }
  }

</script>

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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