Google Maps自定义弹窗平移/缩放地图后自动回到原位置问题咨询
问题原因及解决方案
你的问题核心是Vue响应式机制和Google Maps OverlayView的运行逻辑冲突,加上DOM复用、类重复定义的问题,按以下步骤修改即可修复:
1. 先补全必须的CSS样式
自定义弹窗的容器类必须设置绝对定位,否则坐标计算会不生效:
.popup-container { position: absolute; /* 让弹窗底部中心对准经纬度坐标点 */ transform: translate(-50%, -100%); } .popup-bubble-anchor { position: absolute; width: 100%; bottom: 0; left: 0; } /* 补充你自己的弹窗气泡样式,比如背景、圆角、内边距等 */ .popup-bubble { background: #fff; border-radius: 8px; padding: 12px; box-shadow: 0 2px 10px rgba(0,0,0,0.1); }
2. 调整Popup类的定义逻辑
不要每次点击marker都重复定义Popup类,将类定义提到组件初始化阶段,仅声明一次:
// 组件挂载前就定义好Popup类,不要放在loadCustomPopup里每次调用重复生成 class Popup extends window.google.maps.OverlayView { position; containerDiv; constructor (position, content) { super(); this.position = position; content.classList.add('popup-bubble'); const bubbleAnchor = document.createElement('div'); bubbleAnchor.classList.add('popup-bubble-anchor'); bubbleAnchor.appendChild(content); this.containerDiv = document.createElement('div'); this.containerDiv.classList.add('popup-container'); this.containerDiv.appendChild(bubbleAnchor); Popup.preventMapHitsAndGesturesFrom(this.containerDiv); } onAdd () { this.getPanes().floatPane.appendChild(this.containerDiv); } onRemove () { if (this.containerDiv.parentElement) { this.containerDiv.parentElement.removeChild(this.containerDiv); } } draw () { const divPosition = this.getProjection().fromLatLngToDivPixel( this.position ); const display = Math.abs(divPosition.x) < 4000 && Math.abs(divPosition.y) < 4000 ? 'block' : 'none'; if (display === 'block') { this.containerDiv.style.left = divPosition.x + 'px'; this.containerDiv.style.top = divPosition.y + 'px'; } if (this.containerDiv.style.display !== display) { this.containerDiv.style.display = display; } } }
3. 修改弹窗调用逻辑
解决DOM复用、多弹窗冲突、响应式劫持的问题:
- 每次打开新弹窗先销毁旧弹窗,避免多实例冲突
- 克隆内容DOM节点,不要复用同一个ref对应的DOM
- 不要将popup实例、LatLng对象存为Vue响应式数据(Vue3可以用
markRaw标记非响应式,Vue2不要把这些对象放在data里声明) - 直接用marker自带的position属性,不需要重新生成LatLng实例
loadMarkerInfoWindow (marker) { window.google.maps.event.addListener(marker, 'click', async () => { // 先销毁之前打开的弹窗 if (this.activePopup) { this.activePopup.setMap(null) this.activePopup = null } const targetLatLng = marker.position this.map.panTo(targetLatLng) // 克隆内容DOM,避免复用同一个节点导致冲突 const popupContent = this.$refs.googleMapsCustomPopup.cloneNode(true) const popup = new Popup(targetLatLng, popupContent); popup.setMap(this.map); // 修改injectItemCardToInfoWindow入参,往克隆的DOM里注入内容 this.injectItemCardToInfoWindow(popupContent, marker.item); // 存储弹窗实例,不要放在data的响应式属性里 this.activePopup = popup }); }
内容的提问来源于stack exchange,提问作者joe92
相关产品推荐
相关产品推荐

