Leaflet地图右键菜单点击事件重复触发问题求助
问题原因
每次右键触发contextmenu事件时,你都会给copyCoordinates和copyMarker按钮重复添加点击事件监听器。第一次右键后按钮绑定1个监听器,第二次右键又新增1个,点击时所有绑定的监听器都会执行,因此出现执行次数逐次递增的情况。
解决方案
核心是避免重复绑定事件,以下是两种可行方案:
方案1:将事件绑定移到contextmenu外部,通过变量存储当前坐标
把按钮的点击事件绑定放在地图初始化阶段(仅执行一次),contextmenu事件只负责显示菜单和更新当前右键的坐标,点击按钮时读取该坐标执行操作:
// 存储当前右键的坐标与地图缩放级别 let currentContextLatLng = null; let currentContextZoom = null; // 初始化时绑定按钮点击事件(仅执行一次) document.getElementById('copyCoordinates').addEventListener('click', function() { if (!currentContextLatLng) return; const lat = currentContextLatLng.lat; const lng = currentContextLatLng.lng; const zoom = currentContextZoom; const params = `lat=${lat}&lon=${lng}&zoom=${zoom}`; const newUrl = `${window.location.protocol}//${window.location.host}${window.location.pathname}?${params}`; navigator.clipboard.writeText(newUrl); toastr.success('Copied coordinates to clipboard!', {timeOut: 5000}); document.getElementById('context-menu').style.display = 'none'; }); document.getElementById('copyMarker').addEventListener('click', function() { if (!currentContextLatLng) return; const lat = Math.floor(currentContextLatLng.lat); const lng = Math.floor(currentContextLatLng.lng); const formatted = `"lat": ${lat},\n "lng": ${lng},`; navigator.clipboard.writeText(formatted); toastr.success('Copied coordinates to clipboard!', {timeOut: 5000}); document.getElementById('context-menu').style.display = 'none'; }); // contextmenu事件仅负责显示菜单和更新坐标 map.on('contextmenu', function(e) { const menu = document.getElementById('context-menu'); menu.style.display = 'block'; menu.style.left = `${e.originalEvent.x}px`; menu.style.top = `${e.originalEvent.y}px`; currentContextLatLng = e.latlng; currentContextZoom = map.getZoom(); });
方案2:添加新监听器前先移除旧监听器(使用命名函数)
如果必须在contextmenu事件内绑定事件,需先移除之前的监听器,再添加新的:
// 提前定义命名函数 function copyCoordinates() { if (!this.currentLatLng) return; const lat = this.currentLatLng.lat; const lng = this.currentLatLng.lng; const zoom = this.currentZoom; const params = `lat=${lat}&lon=${lng}&zoom=${zoom}`; const newUrl = `${window.location.protocol}//${window.location.host}${window.location.pathname}?${params}`; navigator.clipboard.writeText(newUrl); toastr.success('Copied coordinates to clipboard!', {timeOut: 5000}); document.getElementById('context-menu').style.display = 'none'; } function copyCoordinatesFormatted() { if (!this.currentLatLng) return; const lat = Math.floor(this.currentLatLng.lat); const lng = Math.floor(this.currentLatLng.lng); const formatted = `"lat": ${lat},\n "lng": ${lng},`; navigator.clipboard.writeText(formatted); toastr.success('Copied coordinates to clipboard!', {timeOut: 5000}); document.getElementById('context-menu').style.display = 'none'; } map.on('contextmenu', function(e) { const menu = document.getElementById('context-menu'); menu.style.display = 'block'; menu.style.left = `${e.originalEvent.x}px`; menu.style.top = `${e.originalEvent.y}px`; const copyBtn = document.getElementById('copyCoordinates'); const markerBtn = document.getElementById('copyMarker'); // 先移除旧监听器,再添加新的 copyBtn.removeEventListener('click', copyCoordinates); markerBtn.removeEventListener('click', copyCoordinatesFormatted); // 给函数绑定当前坐标和缩放级别 const boundCopy = copyCoordinates.bind({ currentLatLng: e.latlng, currentZoom: map.getZoom() }); const boundCopyFormatted = copyCoordinatesFormatted.bind({ currentLatLng: e.latlng, currentZoom: map.getZoom() }); copyBtn.addEventListener('click', boundCopy); markerBtn.addEventListener('click', boundCopyFormatted); });
额外优化建议
- 右键点击页面其他区域时自动隐藏菜单,可添加全局点击监听:
document.addEventListener('click', function(e) { const menu = document.getElementById('context-menu'); if (!menu.contains(e.target)) { menu.style.display = 'none'; } }); - 使用模板字符串(
${变量})替代字符串拼接,代码更简洁易读。
内容的提问来源于stack exchange,提问作者LeJamal
相关产品推荐
相关产品推荐

