Vue3 Google 无法删除地图标记

Vue3 Google Maps marker cannot be removed

我有一个主要用于处理 Vue3 中的 google 地图的自制系统。我没有使用库,因为 none 具有我想要的功能(最终),而且我自己实现起来似乎相对简单(直到这个问题一直如此)。

Map组件如下:

<template>
    <div class="map-container">
        <div class="google-map" ref="map"></div>
        <div>
            <slot></slot>
        </div>
    </div>
</template>

<script>
import { Loader } from '@googlemaps/js-api-loader';

export default {
    props: { 
        latitude: {
            type: [String, Number],
            default: 0
        }, 
        longitude: {
            type: [String, Number],
            default: 0
        },
        zoom: {
            type: Number,
            default: 15
        },
    },
    data(){
        return {
            map: null,
            api: null,
            move: null,
        }
    },
    provide: function () {
        return {
            getMap: this.getMap
        }
    },
    watch: {
        latitude(){ this.updateCenter() },
        longitude(){ this.updateCenter() }
    },
    methods: {
        getMap(callback){
            var self = this;
            function checkForMap() {
              if (self.map) {
                callback(self.map, self.api);
              } else {
                setTimeout(checkForMap, 50);
              }
            }
            checkForMap();
        },
        updateCenter(){
            let center = new this.api.LatLng(this.latitude, this.longitude);
            this.map.panTo(center);
        }
    },  
    mounted(){
        let self = this
        let apiKey = document.getElementById('GOOGLE_MAPS_KEY').value
        let loader = new Loader({
            apiKey:  apiKey,
            version: "weekly",
            libraries: ["geometry"]
        });
        loader.load()
            .then((google) => {
                self.api = google.maps;
                self.map = new google.maps.Map(self.$refs.map, {
                    center: {
                        lat: parseFloat(self.latitude), 
                        lng: parseFloat(self.longitude)
                    },
                    zoom: self.zoom,
                    disableDefaultUI: true,
                });

                // Configure the click listener.
                self.map.addListener("click", (mapsMouseEvent) => {
                    self.$emit('click', mapsMouseEvent)
                });

                // Configure the move listener.
                self.map.addListener("bounds_changed", () => {   
                    if(self.move) clearTimeout(self.move);
                    self.move = setTimeout(() => {
                        let bounds = self.map.getBounds(true);
                        let center = self.map.getCenter();
                        let radius = 100000;

                        if(bounds && center){
                            let northEast = bounds.getNorthEast();
                            radius = self.api.geometry.spherical.computeDistanceBetween(center, northEast);
                        }

                        self.$emit('move', {
                            bounds: bounds,
                            radius: Math.round(radius),
                            center: {
                                latitude: center.lat(),
                                longitude: center.lng()
                            }
                        })
                    }, 800); 
                });
              
            })
            .catch(e => {});
  
    }    
}
</script>

标记组件如下:

<template>
    <div></div>
</template>

<script>
export default {
    props: {
        latitude: String, 
        longitude: String, 
        icon: {
            type: String,
            default: '/images/pin.png'
        }
    },
    data(){
        return {
            map: null,
            api: null,
            marker: null
        }
    },
    inject: ["getMap"],
    watch: {
        latitude(){ this.updatePosition() },
        longitude(){ this.updatePosition() }
    },
    mounted(){
        let self = this
        this.getMap(function(map, api){
            self.map = map;
            self.api = api;

            self.marker = new api.Marker({
                position: new api.LatLng(self.latitude, self.longitude),
                map: map,
                icon: self.icon,
            });

            self.marker.addListener("click", () => {
                self.$emit('click', self.marker)
            });
        })
        
    },
    beforeUnmount(){
        this.marker.setMap(null);
        this.marker = null;
    },
    methods: {
        updatePosition(){
            this.marker.setPosition( new this.api.LatLng( parseFloat(this.latitude), parseFloat(this.longitude) ) );
        }
    }
}
</script>

然后我有一个组件使用这些组件来显示带有标记的地图。

<template>    
    <div>
        <div class="admin-site-map">
            <google-map :center="center" :zoom="15">
                <map-marker v-for="site in sites" :key="site.id" 
                    :latitude="site.latitude" 
                    :longitude="site.longitude" 
                    @click="markerClicked"
                />
            </google-map>        
        </div>
    </div>
</template>

<script>
import GoogleMap from '@/components/Core/Maps/GoogleMap';
import Marker from '@/components/Core/Maps/Marker';
export default {
    components: { GoogleMap, mapMarker: Marker },  
    props: ['sites'],
    data(){
        return {
            center: {lat: 0, lng: 0},
        }
    },
    methods: {
        markerClicked(value){
            console.log('click: ', value)
        }  
    }
}
</script>

当标记(站点)列表发生变化时,我可以看到在已删除的标记上调用了 beforeUnmount 方法,但标记并没有从地图上消失,我什至可以点击在标记上并接收事件中发出的 null 值。 奇怪的是,调用 this.marker.setVisible(false) 确实有效,并且隐藏了标记。 我已经坚持了一段时间,所以任何见解或帮助将不胜感激。谢谢!

多亏了User28,我终于找到了解决办法: 在标记组件上,marker(Google 标记对象保存到的位置)不应该是反应性的 属性。将数据方法更改为

return {
    map: null,
    api: null
}

解决了问题(即删除 marker)。