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
)。
我有一个主要用于处理 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
)。