<template> <div ref="mapContainer" class="map-container"></div> <!-- 自定义右键菜单 --> <div v-if="showContextMenu" :style="contextMenuStyle" class="context-menu"> <div @click="openAddLocationForm">添加地点</div> </div> <!-- 添加地点表单 --> <div v-if="showAddLocationForm" class="add-location-modal"> <div class="modal-content"> <h3>添加地点</h3> <form @submit.prevent="handleSubmit"> <div class="form-row"> <label>经度：</label> <input type="text" :value="formData.lng.toFixed(6)" disabled /> </div> <div class="form-row"> <label>纬度：</label> <input type="text" :value="formData.lat.toFixed(6)" disabled /> </div> <div class="form-row"> <label>说明：</label> <input type="text" v-model="formData.desc" /> </div> <div class="form-actions"> <button type="submit" class="submit-btn">提交</button> </div> </form> </div> </div> </template> <script setup> import{onMounted,onBeforeUnmount,nextTick,ref}from "vue"; import AMapLoader from "@amap/amap-jsapi-loader"; const mapContainer = ref(null); let mapInstance = null; const showContextMenu = ref(false); const contextMenuStyle = ref({}); const showAddLocationForm = ref(false); const formData = ref({lng: 0,lat: 0,desc: ""}); // 高德配置（必须包含 ContextMenu 插件） const amapKey = import.meta.env.VITE_AMAP_KEY; const MAP_CONFIG ={key:amapKey,version: "2.0",plugins: ["AMap.Scale","AMap.ToolBar","AMap.ContextMenu"],}; function openAddLocationForm(){showContextMenu.value = false;showAddLocationForm.value = true}function handleSubmit(){console.log("提交数据:",formData.value);showAddLocationForm.value = false}// 全局右键拦截（仅在地图容器内阻止） const handleGlobalContextMenu = (e) =>{const container = mapContainer.value;if (container && container.contains(e.target)){e.preventDefault()}}; onMounted(async () => {await nextTick(); try {await AMapLoader.load(MAP_CONFIG); const container = mapContainer.value; if (!container) return; mapInstance = new AMap.Map(container,{zoom: 12,center: [114.294706,39.762283],disableDefaultContextMenu: true,}); mapInstance.addControl(new AMap.Scale()); mapInstance.addControl(new AMap.ToolBar()); // 监听高德右键事件 mapInstance.on("rightclick",(e) => {formData.value.lng = e.lnglat.getLng(); formData.value.lat = e.lnglat.getLat(); formData.value.desc = ""; // ✅ 关键：使用 originalEvent 获取真实鼠标位置 const x = e.originalEvent.clientX; const y = e.originalEvent.clientY; // 菜单位置（防止超出视口） const menuWidth = 120; const menuHeight = 40; const left = Math.min(x,window.innerWidth - menuWidth); const top = Math.min(y,window.innerHeight - menuHeight); contextMenuStyle.value = {position: "fixed",left: left + "px",top: top + "px",zIndex: 1000,}; showAddLocationForm.value = false; showContextMenu.value = true;}); // 点击地图关闭菜单 mapInstance.on("click",() => {showContextMenu.value = false;}); // 绑定全局右键拦截 window.addEventListener("contextmenu",handleGlobalContextMenu);} catch (error) {console.error("地图加载失败:",error);}}); onBeforeUnmount(() => {if (mapInstance) mapInstance.destroy(); window.removeEventListener("contextmenu",handleGlobalContextMenu);}); </script> <style> *{margin:0;padding:0;box-sizing:border-box}html,body,#app{width:100%;height:100%;overflow:hidden}.map-container{width:100vw;height:100vh;position:relative}</style> <style scoped> .context-menu{background:#fff;border:1px solid #ddd;border-radius:4px;box-shadow:0 2px 10px #0003;min-width:120px;padding:4px 0;position:fixed;z-index:1000}.context-menu>div{padding:8px 16px;cursor:pointer;font-size:14px}.context-menu>div:hover{background:#f0f9ff}.add-location-modal{position:fixed;right:20px;bottom:20px;z-index:2000}.modal-content{background:#fff;border-radius:8px;box-shadow:0 4px 20px #00000040;padding:20px;width:300px}.form-row{display:flex;margin-bottom:12px;align-items:center}.form-row label{width:60px;font-weight:700}.form-row input{flex:1;padding:6px 8px;border:1px solid #ccc;border-radius:4px}.form-actions{text-align:right}.submit-btn{background:#1890ff;color:#fff;border:none;border-radius:4px;padding:6px 16px;cursor:pointer}.submit-btn:hover{background:#40a9ff}</style> body{margin:0}
