VueJS: Google Maps загружается до того, как данные готовы - как заставить их ждать?(Nuxt) - PullRequest
0 голосов
/ 27 декабря 2018

Это мой первый проект VueJS, и у меня есть vue2-google-maps , но я столкнулся с проблемой при попытке подключить маркеры карты к каналу JSON моего сайта (используя Wordpress REST API), значения Lat и Lng возвращаются undefined или NaN .

В дальнейшемрасследование (благодаря @ QuỳnhNguyễn ниже) кажется, что экземпляр Google Maps запускается до того, как данные будут готовы.Я пытался следить за загрузкой канала перед инициализацией карты, но, похоже, он не работает.

Местоположения маркеров извлекаются из WordPress REST API с использованием JSON и существуют в массиве (местоположения).Массив присутствует и заполняется в Vue Dev Tools (51 запись), но при проверке mount массив пуст.Данные извлекаются на этапе созданный , поэтому я не знаю, почему он не будет готов к подключенной стадии.

Код, о котором идет речь, как показано ниже ...

Шаблон:

<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>
    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>

Ответы [ 3 ]

0 голосов
/ 30 декабря 2018

Похоже, это связано с форматом данных.В соответствии с 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"
    }
  },
  ... 
]

Наличие инициализации массива 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>

Вот демоверсия

0 голосов
/ 30 декабря 2018

Оказывается, что проблема была в грязных данных.

Ответ JSON включал местоположения, которые не должны были быть включены в карту, поэтому каждый раз он сталкивался с записью, в которую не входилиполя ACF, несмотря на то, что я установил в фиде только те данные, для которых было включено true на карте.

Я решил проблему, обработав данные после загрузки фида и создав новый массив (маркеры) из него.используя действительные данные, затем используйте этот, а не исходный массив (местоположения) для размещения маркеров на карте.

Очистка данных:

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 });
                }

            }
        }
    }
}

Затем компонент 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>

Спасибо всем, кто помог мне разобраться в сути проблемы.Сейчас я потрачу некоторое время на переосмысление структуры данных.

0 голосов
/ 29 декабря 2018

vuejs поддерживает директиву v-if для элементов.Я рекомендую вам попробовать следующий фрагмент кода.

<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>
...